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
数组包含关联通道的 id
s,因此您可以执行外键映射。您还已经将频道 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 处理成功的 204 响应并正确映射失败的响应