2014-05-07 22 views
2

似乎在這裏,他們做了變通方法: Relationship between RKObjectMapping and RKEntityMapping能否混合RK​​EntityMapping和RKObjectMapping

可我沒有做任何變通方法混合使用? 謝謝。

編輯:在這裏我添加一個示例JSON。我想要在覈心數據中存儲的是兩個實體Region,但沒有任何關於resultCode或resultDescription的內容。這就是我問我是否可以混合它們的原因。

{ "resultCode": 0, "resultDescription": "OK", "resultContent": [ { "region_id": 0, "description": "USA" }, { "region_id": 1, "description": "Europe" } ] }

+0

把它們混合起來 - 給出JSON和你的數據對象的細節 – Wain

+0

Hello Wain,看看澄清。 – Ricardo

+0

你的問題的答案是什麼? – jAckOdE

回答

1

我自己在使用傳統API時遇到了同樣的問題。這裏是我的解決方案:

響應JSON:

{ 
    "resultCode": 0, 
    "resultDescription": "OK", 
    "resultContent": [ 
     { 
      "region_id": 0, 
      "description": "USA" 
     }, 
     { 
      "region_id": 1, 
      "description": "Europe" 
     } 
    ] 
} 

有此問題的兩個解決方案:

解決方案1:使用帶有@""關鍵路徑對象映射

假設你已經有了屬性名稱與json密鑰名稱相同的託管類別區域

@interface Response 
@property (nonatomic) NSInteger resultCode; 
@property (nonatomic, strong) NSString resultDescription; 
@end 


@implementation Response 
// Make it KV compliant 
@end 

映射

// Response map 
RKObjectMapping* resMap = [RKObjectMapping mappingForClass: [Response class]]; 
[resMap addAttributeMappingsFromArray: @[@"resultCode", @"resultDescription"]]; 

responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:resMap method: RKRequestMethodAny pathPattern:@"" keyPath:@"" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; 

// Region map 
RKEntityMapping* mapping = [RKEntityMapping mappingForEntityForName: name inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]]; 

[mapping addAttributeMappingsFromArray: @[@"region_id", @"description"]]; 
descriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method: RKRequestMethodAny pathPattern:@"/api/regions" keyPath:@"resultContent" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; 

得到的結果

Response* res = [[mappingResult dictionary] objectForKey:[NSNull null]]; 
NSArray* reg = [[mappingResult dictionary] objectForKey:@"resultContent"]; 

解決方案2:使用序列

你可以註冊RKSerialization實現

[RKMIMETypeSerialization registerClass:[NKJsonSerialization class] 
           forMIMEType:RKMIMETypeJSON]; 

而在你的序列化實現中,你可以檢查響應是否是錯誤的響應,並創建一個NSError對象,然後將它發送回Restkit。

@implementation NKJsonSerialization 
+ (id)objectFromData:(NSData *)data error:(NSError **)error 
{ 
    NSError* serializingError = nil; 
    NSMutableDictionary* jsonObject = [NSJSONSerialization 
             JSONObjectWithData:data 
             options:NSJSONReadingMutableContainers 
             error:&serializingError]; 

    // Process if there is no error 
    if (!serializingError) 
    { 
     NSString* resCodeStr = [jsonObject objectForKey:@"resultCode"]; 

     if ([resCodeStr intValue] != 0) { 
     { 
      // Create your NSError for your domain, contain information about response err 
      serializingError == <#new created error#> 
      jsonObject = nil; 
     }else{ 
      [jsonObject removeObjectForKey: @"resultCode"]; 
      [jsonObject removeObjectForKey: @"resultDescription"]; 
      serializingError = nil; 
     } 
    } 

    *error = serializingError; 
    return jsonObject; 
} 

如果響應包含錯誤代碼,在您的要求回調,RestKit將返回底層錯誤NSError對象是你在序列化過程剛剛創建的錯誤。

此解決方案的優點是您不必關心映射響應狀態。錯誤的響應將會(應該)作爲NSError來處理。

如果json對象包含頂級數據對象(關鍵路徑@「」),您仍然可以使用映射來獲得它,而不會產生密鑰衝突,因爲它會在解決方案#1中發生。

+0

/api/region。它來自哪裏 – khunshan

+0

它應該是您的請求路徑。 – jAckOdE

1

我不知道你問究竟.. RKEntityMapping用於映射到核心數據實體,並且RKObjectMapping用來只是映射到正規對象表示。所以也許問題是,你是否在使用核心數據?

+0

你好EAB,看到澄清。 – Ricardo

0

好的,經過幾次測試,我意識到RestKit將RKEntityMapping保存在覈心數據中,但不保存RKObjectMapping。它完美的作品。我愛RestKit :)

+0

你介意分享你的映射代碼嗎?有人可能會發現它有幫助 – jAckOdE

+0

你告訴我們的一樣。只是不要做任何事情。如果您想要將它們保存在覈心數據或RKEntityMapping中(如果不想保存它們),請聲明RKObjectMapping。 RestKit非常棒。 – Ricardo

1

您需要定義兩個單獨的描述符RKObjectMapping & RKEntityMapping對象,你的情況爲StatusMapping & RegionMapping然後將它們添加到的ObjectManager,它像魅力(我給你的示例代碼和類做到這一點):

這樣定義ResponseStatus類:

// ...

ResponseStatus.h

// ...

@interface ResponseStatus : NSObject 

@property (nonatomic) BOOL resultCode; 
@property (nonatomic, strong) NSString *resultDescription; 

+ (RKObjectMapping *)rkObjectMappingForResponse:(BOOL)includeAll; 
+ (RKObjectMapping *)rkObjectMappingForRequest:(BOOL)includeAll; 
+ (NSDictionary *)rkAttributeMappingsDictionary:(BOOL)request includeAll:(BOOL)includeAll; 

@end 

// ...

ResponseStatus.m

// ...

@implementation ResponseStatus 

    + (RKObjectMapping *)rkObjectMappingForResponse:(BOOL)includeAll { 
     RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ResponseStatus class]]; 
     [mapping addAttributeMappingsFromDictionary:[self rkAttributeMappingsDictionary:NO includeAll:includeAll]]; 

     if (includeAll) { 
     } 

     return mapping; 
    } 

    + (RKObjectMapping *)rkObjectMappingForRequest:(BOOL)includeAll { 
     RKObjectMapping *mapping = [RKObjectMapping requestMapping]; 
     [mapping addAttributeMappingsFromDictionary:[self rkAttributeMappingsDictionary:YES includeAll:includeAll]]; 

     if (includeAll) { 
     } 

     return mapping; 
    } 

    + (NSDictionary *)rkAttributeMappingsDictionary:(BOOL)request includeAll:(BOOL)includeAll { 
     NSMutableDictionary *dic = [NSMutableDictionary dictionary]; 

     if (includeAll) { 
      [dic addEntriesFromDictionary:@{ 
       @"resultCode": @"resultCode", 
       @"resultDescription": @"resultDescription", 
      }]; 
     } 

     return dic; 
    } 

    @end 

定義一個描述符映射爲您ResponseStatus (結果)

NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx 

RKResponseDescriptor *statusResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[ResponseStatus rkObjectMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:@"" statusCodes:statusCodes]; 

定義一個描述符映射爲您RKEntityMapping

RKResponseDescriptor *gameResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[Game rkEntityMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:@"games" statusCodes:statusCodes]; 

添加響應描述符的ObjectManager

[objectManager addResponseDescriptorsFromArray:@[gameResponseDescriptor, statusResponseDescriptor]]; 

這是如何處理測繪成果

RKObjectRequestOperation *operation = [objectManager managedObjectRequestOperationWithRequest:requestObject managedObjectContext:managedObjectContext success: ^(RKObjectRequestOperation *operation, RKMappingResult *result) { 

    if ([RKUtils isResponseStatusError:[result array]]) 
     { 
     //..  
     } 

     } failure: ^(RKObjectRequestOperation *operation, NSError *error) 
     { 
     NSLog(@"Failed with error: %@", [error localizedDescription]); 
     }]; 


+ (BOOL)isResponseStatusError:(NSArray *)itemsList { 
    if ([itemsList count] != 1) { 
     return NO; 
    } 

    id object = itemsList[0]; 

    if ([object isKindOfClass:[ResponseStatus class]]) { 
     ResponseStatus *responseStatus = object; 
     if (!responseStatus.resultCode) { 
      NSLog(@"Error : %@", responseStatus.message); 
      return YES; 
     } 
    } 

    return NO; 
} 

並作出REST電話,希望這有助於。

+0

以及你如何處理映射結果? – jAckOdE

+0

jAckOdE我已經更新了我的答案,請查看。 –

+1

您不應該認爲'ResponseStatus'會作爲數組中的第一個對象。在快速搜索後,我認爲這應該是更正確的處理結果的方法:'[[result dictionary] objectForKey:[NSNull null]]'@根中的根對象'''keypath將設置爲'NSNull'鍵(已測試) – jAckOdE

1

在這種情況下,您不需要混合它們。當您創建您的響應描述符時,您將關鍵路徑設置爲resultContent,並僅使用實體映射。

可以在某些方面混合映射類型,但這通常需要根據具體情況進行考慮。通常你會使用多個響應描述符來保持映射分離,然後將結果合併爲後處理。

+0

好主意,這也是一種可能性,但就我的理解而言,我還需要創建一個動態映射以捕獲錯誤。 – Ricardo

+1

你的問題是因爲你不想錯誤信息。您可以使用動態映射或2個響應描述符。 – Wain