【问题标题】:RestKit many-to-many mapping, how to?RestKit 多对多映射,怎么做?
【发布时间】:2012-06-25 21:23:01
【问题描述】:

我正在开发我的第一个 RestKit 应用程序,我使用 CoreData 进行本地缓存。在其中,我在 Post > 类别之间建立了多对多的关系。这种关系称为帖子和类别。

在我的 Post JSON 调用中,我得到如下类别的 ID:{"post": [...] "categories":[1,4] [...],其中 1 和 4 是 ID。

我有一个继承自 NSManagedObject 的自定义 Post 模型对象,其中我有一个类别属性,如下所示:

@interface Post : NSManagedObject

[...]
@property (nonatomic, retain) NSSet *categories;
[...]

我在自定义类别模型对象中做同样的事情。

我的映射目前如下所示:

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];

当我运行它时,我得到了错误:'[<__NSCFNumber 0x6c625e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key id.'

如果有人能给我任何关于如何映射这种关系的线索,我将不胜感激。

【问题讨论】:

    标签: ios core-data many-to-many restkit


    【解决方案1】:

    出现错误是因为您的 JSON 将每个类别作为主键返回,即:一个 NSNumber。但是您的映射需要一个嵌套对象(将转换为 KVC 对象)。当您的地图尝试访问 KVC 对象(实际上是一个 NSNumber)上的属性“id”时,它会像这样崩溃。

    我不确定它是否会起作用,但您可以尝试以下方法:

    RKManagedObjectMapping* categoryMapping = //something
    categoryMapping.primaryKeyAttribute = @"categoryId";
    [categoryMapping mapKeyPath: @"" toAttribute: @"categoryId"];
    
    [..]
    
    [postMapping mapKeyPath: @"categories" toRelationship: @"categories" withMapping: categoryMapping]; 
    

    通常,您会使用 [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
    

    .m

    #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
    

    【讨论】:

    • 谢谢,决定将 JSON 更改为 "categories":[{"category_id":1},{"category_id":4}],您知道我应该如何以及何时填充联接表吗?我目前只获取类别。谢谢!
    • 什么是连接表?这实际上是另一个问题。
    • 好的,谢谢。连接表是两个多对多实体之间的表,其中存储了两个表的主键。当我加载帖子时,它实际上填充了这个连接表,但由于某种原因,它也会在我的 Category 模型中创建新行。可能会针对该问题提出另一个问题。但是更改 JSON 似乎有所帮助,不再出现错误。谢谢!
    • 针对上述评论提出了一个新问题:stackoverflow.com/questions/11227548/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2013-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多