RestKit .22:无法成功映射与嵌套 JSON 的关系

Posted

技术标签:

【中文标题】RestKit .22:无法成功映射与嵌套 JSON 的关系【英文标题】:RestKit .22: Unable to successfully map relationship with nested JSON 【发布时间】:2013-12-15 21:42:58 【问题描述】:

我这几天一直在与 RestKit 进行关系映射。我可以很好地得到一个对象,但是嵌套的 JSON 数据数组没有被映射并且查看跟踪日志我找不到任何错误。尽管很痛,但我承认它已经使我受益匪浅。我已经查看了尽可能多的示例,并根据其他人在他们的情况下所做的尝试了不同的解决方案,但没有任何效果。我尝试按照 RestKit 文档随附的 RKGist 示例进行操作,但不幸的是,尚未编写关系映射部分,那里只有占位符。

这是我正在使用的 JSON 示例响应:


"stat": 
    "code": 200
,
"data": 
    "channel": 
        "_id": "68413dzz39f4843t8500000d",
        "desc": "...",
        "name": "...",
        "owner": 
            "_id": "584ege8239f4883f6200000b",
            "name": "..."
        ,
        "count": 
            "invited": 0,
            "joined": 1,
            "subscribers": 0,
            "posts": 0,
            "messages": 0
        ,
        "access": "PUB"
    ,
    "affiliation": "...",
    "member_statuses": [
        
            "channel": 
                "_id": "68413dzz39f4843t8500000d",
                "name": "..."
            ,
            "owner": 
                "_id": "584ege8239f4883f6200000b",
                "dname": "...",
                "name": "..."
            ,
            "type": "...",
            "message": "This is the message text",
            "_id": "52222e3039f4884tkk00000e",
            "taken": "2013-11-11T20:23:45.938Z",
            "access": "PUB"
        
    ]


我还无法发布图片,因为这是我无法找到答案的第一个问题。但是两个相关的 Core Data 模型和 NSManagedObject 子类是:

THChannel.h

我已经建立了一个名为posts 的关系,其目的地为THPost,其倒数为post。我选择类型为To Many,因为多个帖子可以属于一个频道

@class THPost, THUser;

@interface THChannel : NSManagedObject

@property (nonatomic, retain) NSString * accessCode;
@property (nonatomic, retain) NSString * channelId;
@property (nonatomic, retain) NSNumber * countComments;
@property (nonatomic, retain) NSNumber * countInvited;
@property (nonatomic, retain) NSNumber * countJoined;
@property (nonatomic, retain) NSNumber * countMessages;
@property (nonatomic, retain) NSNumber * countPhotos;
@property (nonatomic, retain) NSNumber * countPosts;
@property (nonatomic, retain) NSNumber * countSubscribers;
@property (nonatomic, retain) NSDate * createdAt;
@property (nonatomic, retain) NSString * desc;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) THUser *owner;
@property (nonatomic, retain) NSSet *posts;
@end

@interface THChannel (CoreDataGeneratedAccessors)

- (void)addPostsObject:(THPost *)value;
- (void)removePostsObject:(THPost *)value;
- (void)addPosts:(NSSet *)values;
- (void)removePosts:(NSSet *)values;

@end

THPost.h

我已经建立了一个名为post 的关系,其目的地为THChannel,其倒数为posts。我选择类型为To One,因为多个帖子可以属于一个频道

@class THChannel, THUser;

@interface THPost : NSManagedObject

@property (nonatomic, retain) NSString * postId;
@property (nonatomic, retain) NSString * channelId;
@property (nonatomic, retain) NSString * ownerTypeCode;
@property (nonatomic, retain) NSString * ownerId;
@property (nonatomic, retain) NSString * postTypeCode;
@property (nonatomic, retain) NSString * messageText;
@property (nonatomic, retain) NSDate * createdAt;
@property (nonatomic, retain) NSDate * takenAt;
@property (nonatomic, retain) NSString * accessTypeCode;
@property (nonatomic, retain) THChannel *post;
@property (nonatomic, retain) THUser *owner;

@end

AppDelegate.m

// Log all HTTP traffic with request and response bodies
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);

// Log debugging info about Core Data
RKLogConfigureByName("RestKit/CoreData", RKLogLevelDebug);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);

NSError *error = nil;

NSURL *baseURL = [NSURL URLWithString:API_BASE_URL];
NSIndexSet *successStatusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx status codes

[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

RKObjectManager *manager = [RKObjectManager managerWithBaseURL:baseURL];

// Initialize managed object store
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];

[managedObjectStore createPersistentStoreCoordinator];
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MyApp.sqlite"];
NSDictionary *options = @  NSMigratePersistentStoresAutomaticallyOption: @(NO),
                            NSInferMappingModelAutomaticallyOption: @(NO) ;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:options error:&error];
if (! persistentStore) 
    RKLogError(@"Failed adding persistent store at path '%@': %@", path, error);


[managedObjectStore createManagedObjectContexts];

RKEntityMapping *channelEntityMapping = [RKEntityMapping mappingForEntityForName:@"THChannel" inManagedObjectStore:managedObjectStore];

channelEntityMapping.identificationAttributes = @[ @"channelId" ];
[channelEntityMapping addAttributeMappingsFromDictionary:@ @"_id": @"channelId",
                                                            @"name": @"name",
                                                            @"desc": @"desc",
                                                            @"access": @"accessCode",
                                                            @"nmupl": @"nonMemberUploads",
                                                            @"meta.created": @"createdAt",
                                                            @"affiliation": @"viewerAffiliationCode",
                                                            @"canPost": @"viewerCanPost",
                                                            @"count.subscribers": @"countSubscribers",
                                                            @"count.comments": @"countComments",
                                                            @"count.posts": @"countPosts",
                                                            @"count.photos": @"countPhotos",
                                                            @"count.messages": @"countMessages",
                                                            @"count.joined": @"countJoined",
                                                            @"count.invited": @"countInvited" ];

RKEntityMapping *postEntityMapping = [RKEntityMapping mappingForEntityForName:@"THPost" inManagedObjectStore:managedObjectStore];

postEntityMapping.identificationAttributes = @[ @"postId" ];
[postEntityMapping addAttributeMappingsFromDictionary:@ @"_id": @"postId",
                                                         @"channel._id": @"channelId",
                                                         @"type": @"postTypeCode",
                                                         @"message": @"messageText",
                                                         @"meta.created": @"createdAt",
                                                         @"taken": @"takenAt",
                                                         @"access": @"accessTypeCode"
                                                         ];




[channelEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"member_statuses" toKeyPath:@"posts" withMapping:postEntityMapping]];

NSEntityDescription *postEntity = [NSEntityDescription entityForName:@"THPost" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext];
 NSRelationshipDescription *postRelationship = [postEntity relationshipsByName][@"post"];
 RKConnectionDescription *connection2 = [[RKConnectionDescription alloc] initWithRelationship:postRelationship attributes:@ @"channelId": @"channelId" ];
 [postEntityMapping addConnection:connection2];

RKResponseDescriptor *channelsOverviewObjectDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:channelEntityMapping
                                                                                              method:RKRequestMethodAny
                                                                                         pathPattern:@"/channels/:channelID"
                                                                                             keyPath:@"data.channel"
                                                                                         statusCodes:successStatusCodes];

[manager addResponseDescriptorsFromArray:@[channelsOverviewObjectDescriptor]];

// Set the default store shared instance
manager.managedObjectStore = managedObjectStore;

[RKObjectManager setSharedManager:manager];

【问题讨论】:

【参考方案1】:

问题是:

[channelEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"member_statuses" toKeyPath:@"posts" withMapping:postEntityMapping]];

用于嵌套数据,而这不是您所拥有的。您有 2 个不同的字典,其中包含 2 种不同类型的数据。

幸运的是,member_statuses 数组包含关联通道的 ids,因此您可以执行外键映射。您还已经将频道 ID 映射到帖子中(这是另一个必需的部分)。为此,您将需要 2 个对同一响应进行操作的响应描述符。 1个用于频道,1个用于帖子。应该建立与通道的连接的是 post 映射(因此从通道映射中删除属性映射)。

外键映射应该设置如下:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"THPost" inManagedObjectContext:managedObjectContext];
NSRelationshipDescription *relationship = [entity relationshipsByName][@"post"];
RKConnectionDescription *connection = [[RKConnectionDescription alloc] initWithRelationship:e

关系属性:@@"channelId":@"channelId" ];

然后将连接添加到post映射中。

【讨论】:

Wain,在未来的某一天,你会回顾过去,想知道你是否在这一生中有所作为。我会继续告诉你是的,是的,你做到了。你救了我的理智。您使用我需要的附加响应描述符一针见血。正在建立两个实体之间的连接,但由于缺少响应描述符,帖子没有被拾取和保存。在您的解释之后,为什么这些数据不被视为嵌套数据是有道理的,但是随着一切的发生,这很难看出。感谢您花时间回答。谢谢!

以上是关于RestKit .22:无法成功映射与嵌套 JSON 的关系的主要内容,如果未能解决你的问题,请参考以下文章

RestKit 0.20:映射复杂的动态嵌套 JSON

无法使用 RestKit 处理成功的 204 响应并正确映射失败的响应

RestKit 将未嵌套关系映射到拥有对象

RestKit嵌套的一对多关系映射很慢

restkit 映射嵌套数组为空(带有 json 响应的嵌套 restkit 请求)

RESTKit 的问题,无法正确映射