And*_*ers 5 many-to-many core-data ios restkit
我正在研究我的第一个RestKit应用程序,并使用CoreData进行本地缓存.在其中我有Post << --- >> Category之间的多对多关系.这种关系称为帖子和类别.
在我的Post JSON调用中,我获得了类似这样的类别{"post": [...] "categories":[1,4] [...]
的id:,其中1和4是id.
我有一个Post
继承自定义的模型对象NSManagedObject
,在其中我有类别的属性,如下所示:
@interface Post : NSManagedObject
[...]
@property (nonatomic, retain) NSSet *categories;
[...]
Run Code Online (Sandbox Code Playgroud)
我在自定义的Category模型对象中做同样的事情.
我的映射目前看起来像这样:
RKManagedObjectMapping *categoryMapping = [RKManagedObjectMapping mappingForClass:[Category class] inManagedObjectStore:objectManager.objectStore];
categoryMapping.primaryKeyAttribute = @"categoryId";
categoryMapping.rootKeyPath = @"categories";
[categoryMapping mapKeyPath:@"id" toAttribute:@"categoryId"];
[categoryMapping mapKeyPath:@"name" toAttribute:@"name"];
[...]
RKManagedObjectMapping* postMapping = [RKManagedObjectMapping mappingForClass:[Post class] inManagedObjectStore:objectManager.objectStore];
postMapping.primaryKeyAttribute = @"postId";
postMapping.rootKeyPath = @"post";
[postMapping mapKeyPath:@"id" toAttribute:@"postId"];
[...]
[postMapping mapKeyPath:@"created_at" toAttribute:@"createdAt"];
[...]
// Categories many-to-many.
[postMapping mapKeyPath:@"categories" toRelationship:@"categories" withMapping:categoryMapping];
Run Code Online (Sandbox Code Playgroud)
当我运行这个时,我得到错误: '[<__NSCFNumber 0x6c625e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key id.'
如果有人能给我任何关于如何映射这种关系的线索,我将非常感激.
出现错误是因为您的 JSON 返回每个类别作为主键,即:一个 NSNumber。但是您的映射需要一个嵌套对象(它将转换为 KVC 对象)。当你的地图尝试访问 KVC 对象(实际上是 NSNumber)上的属性“id”时,它会像这样崩溃。
我不确定它是否有效,但你可以尝试这样的事情:
RKManagedObjectMapping* categoryMapping = //something
categoryMapping.primaryKeyAttribute = @"categoryId";
[categoryMapping mapKeyPath: @"" toAttribute: @"categoryId"];
[..]
[postMapping mapKeyPath: @"categories" toRelationship: @"categories" withMapping: categoryMapping];
Run Code Online (Sandbox Code Playgroud)
通常,您会使用 [RKManagedObjectMapping connectRelationship:withObjectForPrimaryKeyAttribute:] 方法,但我不知道这是否适用于多对多关系。您可能需要修改源代码才能执行此操作。要查看的代码位于 [RKManagedObjectMappingOperation connectRelationship:] 内部。
否则,如果可能的话,我建议您更改 JSON 源,以便类别数组如下所示: "categories" : [{"categoryID: 1}, {"categoryID" : 4}]。如果无法更改源,您可以使用委托方法或我在下面给出的 RKObjectLoader 扩展手动修改数据:
。H
typedef void(^RKObjectLoaderWillMapDataBlock)(id* mappableData);
@interface RKObjectLoader (Extended)
@property (nonatomic, copy) RKObjectLoaderWillMapDataBlock onWillMapData;
@end
Run Code Online (Sandbox Code Playgroud)
.米
#import "RKObjectLoader+Extended.h"
#import <objc/runtime.h>
NSString* kOnWillMapDataKey = @"onWillMapData";
@implementation RKObjectLoader (Extended)
- (RKObjectLoaderWillMapDataBlock) onWillMapData {
return objc_getAssociatedObject(self, &kOnWillMapDataKey);
}
- (void) setOnWillMapData:(RKObjectLoaderWillMapDataBlock) block {
objc_setAssociatedObject(self, &kOnWillMapDataKey, block, OBJC_ASSOCIATION_COPY);
}
- (RKObjectMappingResult*)mapResponseWithMappingProvider:(RKObjectMappingProvider*)mappingProvider toObject:(id)targetObject inContext:(RKObjectMappingProviderContext)context error:(NSError**)error {
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:self.response.MIMEType];
NSAssert1(parser, @"Cannot perform object load without a parser for MIME Type '%@'", self.response.MIMEType);
// Check that there is actually content in the response body for mapping. It is possible to get back a 200 response
// with the appropriate MIME Type with no content (such as for a successful PUT or DELETE). Make sure we don't generate an error
// in these cases
id bodyAsString = [self.response bodyAsString];
RKLogTrace(@"bodyAsString: %@", bodyAsString);
if (bodyAsString == nil || [[bodyAsString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) {
RKLogDebug(@"Mapping attempted on empty response body...");
if (self.targetObject) {
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionaryWithObject:self.targetObject forKey:@""]];
}
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionary]];
}
id parsedData = [parser objectFromString:bodyAsString error:error];
if (parsedData == nil && error) {
return nil;
}
// Allow the delegate to manipulate the data
if ([self.delegate respondsToSelector:@selector(objectLoader:willMapData:)]) {
parsedData = AH_AUTORELEASE([parsedData mutableCopy]);
[(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoader:self willMapData:&parsedData];
}
if( self.onWillMapData ) {
parsedData = AH_AUTORELEASE([parsedData mutableCopy]);
self.onWillMapData(&parsedData);
}
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider];
mapper.targetObject = targetObject;
mapper.delegate = (id<RKObjectMapperDelegate>)self;
mapper.context = context;
RKObjectMappingResult* result = [mapper performMapping];
// Log any mapping errors
if (mapper.errorCount > 0) {
RKLogError(@"Encountered errors during mapping: %@", [[mapper.errors valueForKey:@"localizedDescription"] componentsJoinedByString:@", "]);
}
// The object mapper will return a nil result if mapping failed
if (nil == result) {
// TODO: Construct a composite error that wraps up all the other errors. Should probably make it performMapping:&error when we have this?
if (error) *error = [mapper.errors lastObject];
return nil;
}
return result;
}
@end
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1334 次 |
最近记录: |