2012-06-24 13 views
5

İlk RestKit uygulamasında çalışıyorum ve yerel önbellekleme için CoreData kullanıyorum. İçinde < < --- >> kategorisi arasında çoktan çoğa ilişkisi var. İlişki postalar ve kategoriler olarak adlandırılır.RestKit çoktan çoğa eşleme nasıl yapılır?

Post JSON çağrısında, bu gibi kategoriler için kimlik aldım: {"post": [...] "categories":[1,4] [...], burada 1 ve 4, kimlikler.

@interface Post : NSManagedObject 

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

Özel bir Kategori modeli nesne aynı şeyi yapmak:

İçinde böyle kategoriler için bir özellik var, NSManagedObject devralan bir özel Post modeli nesnesi var.

Benim eşleştirmeleri anda şöyle görünür: '[<__NSCFNumber 0x6c625e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key id.'

kimse bana bu ilişkiyi eşlemek için nasıl herhangi bir ipucu verebilir Ben gerçekten takdir ediyorum:

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

Bunu çalıştırdığınızda hatası alıyorum.

cevap

2

JSON'unuz her kategoriyi birincil anahtar olarak döndürdüğünden dolayı bir hata vardır, örn .: bir NSNumber. Ancak eşlemeniz, iç içe bir nesneyi (bir KVC nesnesine dönüştürülecek) bekler. Haritanız KVC nesnesindeki "id" özelliğine erişmeye çalıştığında (aslında bir NSNumber), bu şekilde çökecektir. işe yarayacak eğer

emin değilim, ama böyle bir şey deneyebilirsiniz: Eğer [: withObjectForPrimaryKeyAttribute: RKManagedObjectMapping connectRelationship] kullanmak istiyorsunuz,

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

[..] 

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

Normalde yöntemi, ama bilmiyorum Bu çoktan çoğa ilişki üzerinde çalışacaksa. Bunu yapmak için kaynak kodunu değiştirmeniz gerekebilir. Bakılacak kod, [RKManagedObjectMappingOperation connectRelationship:] içinde.

Aksi takdirde, JSON kaynağınızı değiştirmenizi öneririm, böylece kategori dizisi şöyle olur: "kategoriler": [{"categoryID: 1}, {" categoryID ": 4}]. olası aşağıda verdik el temsilci yöntemleri veya RKObjectLoader uzantısını kullanarak verileri değiştirebilirsiniz, değiştirmek için:

.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

teşekkür, değiştirmeye karar verdi JSON "kategorilere": [{"category_id": 1}, {"category_id": 4}] ', birleştirme tablosunu nasıl ve ne zaman doldurmam gerektiğini biliyor musunuz? Şu anda sadece kategorileri getiriyorum. Teşekkürler! – Anders

+0

Birleştirme tablosu nedir? Bu aslında başka bir soru. –

+0

Evet, teşekkürler. Birleştirme tablosu, iki tablodan birincil varlıkların depolandığı çoktan çoğa varlıklar arasındaki tablodur. Gönderiyi yüklediğimde aslında bu birleştirme tablosunu doldurur, ancak aynı zamanda Kategori modelimde de bazı nedenlerle yeni satırlar oluşturur. Muhtemelen bu konuyla ilgili başka bir soru soracaktır. Ancak JSON'un değiştirilmesi yardımcı oldu, artık hata yok. Teşekkürler! – Anders