2012-06-24 30 views
5

Tôi đang làm việc trên ứng dụng RestKit đầu tiên của mình và tôi sử dụng CoreData cho bộ nhớ đệm cục bộ. Trong đó tôi có mối quan hệ nhiều-nhiều giữa Bài viết < < --- >> Danh mục. Mối quan hệ này được gọi là bài đăng và danh mục.RestKit lập bản đồ nhiều người, làm cách nào?

Trong cuộc gọi JSON của tôi, tôi nhận được id cho các danh mục như sau: {"post": [...] "categories":[1,4] [...], trong đó 1 và 4 là các id.

Tôi có một tùy chỉnh Post mô hình đối tượng được thừa kế từ NSManagedObject, trong đó tôi có một tài sản cho các hạng mục, như thế này:

@interface Post : NSManagedObject 

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

tôi làm điều tương tự trong một đối tượng tùy chỉnh loại mô hình.

ánh xạ của tôi hiện trông như thế này:

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

Khi tôi chạy này, tôi nhận được lỗi: '[<__NSCFNumber 0x6c625e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key id.'

Tôi thực sự sẽ đánh giá cao nếu có ai có thể cho tôi bất kỳ manh mối về cách để lập bản đồ mối quan hệ này.

Trả lời

2

Có lỗi là do JSON của bạn trả về từng danh mục dưới dạng khóa chính, ví dụ: NSNumber. Nhưng ánh xạ của bạn mong đợi một đối tượng lồng nhau (mà sẽ được chuyển đổi thành một đối tượng KVC). Khi bản đồ của bạn cố truy cập thuộc tính "id" trên đối tượng KVC (thực tế là một NSNumber), nó sẽ sụp đổ như thế này.

Tôi không chắc chắn nếu nó sẽ làm việc, nhưng bạn có thể thử một cái gì đó như thế này:

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

[..] 

[postMapping mapKeyPath: @"categories" toRelationship: @"categories" withMapping: categoryMapping]; 

Thông thường, bạn sẽ sử dụng [RKManagedObjectMapping connectRelationship: withObjectForPrimaryKeyAttribute:] phương pháp, nhưng tôi không biết nếu điều này sẽ làm việc trên một mối quan hệ nhiều-nhiều. Bạn có thể phải sửa đổi mã nguồn để thực hiện việc này. Mã để xem xét là bên trong [RKManagedObjectMappingOperation connectRelationship:].

Nếu không, nếu có thể, tôi khuyên bạn nên thay đổi nguồn JSON để mảng danh mục giống như sau: "danh mục": [{"categoryID: 1}, {" categoryID ": 4}]. có thể thay đổi, bạn có thể sửa đổi dữ liệu bằng tay bằng cách sử dụng phương pháp đại biểu hoặc phần mở rộng RKObjectLoader tôi đã đưa ra dưới đây:

.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 
+0

Cảm ơn, quyết định thay đổi JSON tới "" danh mục ": [{" category_id ": 1}, {" category_id ": 4}]', bạn có biết cách thức và thời điểm tôi nên điền bảng tham gia không? Tôi hiện chỉ tìm nạp các danh mục. Cảm ơn! – Anders

+0

Bảng kết nối là gì? Đây thực sự là một câu hỏi khác. –

+0

Vâng, cảm ơn. Một bảng nối là bảng giữa hai thực thể nhiều đến nhiều, trong đó các khóa chính từ hai bảng được lưu trữ. Nó thực sự populates này tham gia bảng khi tôi tải bài viết, nhưng sau đó nó cũng tạo ra hàng mới trong mô hình thể loại của tôi vì lý do nào. Có lẽ sẽ hỏi một câu hỏi khác cho vấn đề đó. Nhưng việc thay đổi JSON dường như có ích, không có lỗi nữa. Cảm ơn! – Anders

Các vấn đề liên quan