2012-01-15 44 views
15

是否有可能通過RestKit將JSON的NSString反序列化爲對象?我檢查了API列表here,並找不到可用於此目的的內容。我能找到的最接近的是解析輸入後返回NSDictionary的各種解析器類。我假設RestKit在下載響應後使用這些解析器,所以我認爲該功能在RestKit中可用,但不公開公開。通過RestKit將JSON的本地NSString反序列化爲對象

如果我沒有遺漏任何東西,而且這個功能沒有公開,那麼替代方案是什麼?兩個明顯的看起來不太有希望:得到結果NSDictionary並嘗試反序列化我自己(有效地重新實現RestKit)或嘗試潛入RestKit源代碼並查看它是否可以以某種方式暴露(看起來很乏味和容易出錯)。

在此先感謝您的幫助。

PS:其思想是反序列化對象上的字符串屬性實際上是另一組對象的JSON表示(某種意義上是嵌入式JSON),並且在運行時按需進行反序列化。

回答

9

相當 「簡單」:

NSString *stringJSON; 
... 

RKJSONParserJSONKit *parser; 
NSError *error= nil; 
parser= [[[RKJSONParserJSONKit alloc] init] autorelease]; 
MyManagedObject *target; 
target= [MyManagedObject object]; 

NSDictionary *objectAsDictionary; 
RKObjectMapper* mapper; 
objectAsDictionary= [parser objectFromString:stringJSON error:&error]; 
mapper = [RKObjectMapper mapperWithObject:objectAsDictionary 
          mappingProvider:[RKObjectManager sharedManager].mappingProvider]; 
mapper.targetObject = target; 
RKObjectMappingResult* result = [mapper performMapping]; 
NSLog(@"%@", [result asObject]); 
0
+0

我知道這些解析器類。他們將字符串解析爲「NSDictionary」,這是整個反序列化過程的第一部分。我需要使用一個字符串並輸出映射對象的功能。換句話說,在RestKit按順序執行的三件事中(下載響應,解析下載的字符串,映射對象),我需要的只是最後兩項。 – alokoko 2012-01-16 10:10:16

+0

嘿,我有同樣的問題。我有一些JSON需要映射到我的模型(NSManagedObject)。你有沒有找到解決方案? – 2012-01-21 13:10:55

+0

@MikeBevz:我寫了自己的映射器。 :-)我寫了更多的細節作爲對這個問題的回答。 – alokoko 2012-01-21 22:00:25

0

通過沒有任何答案的觀點來判斷,似乎這個設施在RestKit中還不存在。我沒有花費更多的時間來弄清楚如何完成映射,而是使用JsonKit解析器的輸出編寫了自己的映射器,並刪除了對RestKit的依賴(使用內置類進行網絡活動)。現在我的映射器不是通用的(它對json中對象的佈局和名稱有一些依賴關係),但它適用於項目。稍後我可能會回來,並在稍後將它變成一個更通用的對象映射庫。

編輯:這是被選中的答案,因爲沒有其他答案作爲此答案的日期(2012年1月21日)。從那時起,我停止在iOS上工作,並再也沒有訪問過這個問題。現在我正在選擇Ludovic的答案,因爲另一位用戶的評論以及對該答案的讚揚。

+2

這是爲什麼選擇的答案? Ludovic的解決方案效果很好! – 2012-08-18 00:24:43

+0

@Kyle:這是被選中的答案,因爲在答覆日期(2012年1月21日)之前沒有其他答案。從那時起,我停止在iOS上工作,並再也沒有訪問過這個問題。儘管我目前無法自己覈實答案,但我正在選擇Ludovic的答案,因爲您的評論。 – alokoko 2013-01-27 00:25:07

1

更iOS 5以上的面向答案:

NSString* JSONString = jsonString; 
NSString* MIMEType = @"application/json"; 
NSError* error = nil; 
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:MIMEType]; 
id parsedData = [parser objectFromString:JSONString error:&error]; 
if (parsedData == nil && error) { 
    NSLog(@"ERROR: JSON parsing error"); 
} 

RKObjectMappingProvider* mappingProvider = [RKObjectManager sharedManager].mappingProvider; 
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider]; 
RKObjectMappingResult* result = [mapper performMapping]; 
if (result) { 

    NSArray *resultArray = result.asCollection; 

    MyObject *object = [resultArray lastObject]; 
    NSLog(@"My Object: %@", object); 
} 
8

由於RestKit 0.20.0-pre2

NSString* JSONString = @"{ \"name\": \"The name\", \"number\": 12345}"; 
NSString* MIMEType = @"application/json"; 
NSError* error; 
NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; 
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:MIMEType error:&error]; 
if (parsedData == nil && error) { 
    // Parser error... 
} 

AppUser *appUser = [[AppUser alloc] init]; 

NSDictionary *mappingsDictionary = @{ @"someKeyPath": someMapping }; 
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary]; 
mapper.targetObject = appUser; 
NSError *mappingError = nil; 
BOOL isMapped = [mapper execute:&mappingError]; 
if (isMapped && !mappingError) { 
    // Yay! Mapping finished successfully 
    NSLog(@"mapper: %@", [mapper representation]); 
    NSLog(@"firstname is %@", appUser.firstName); 
} 
+0

您是否知道如何從已配置的RKObjectManager中執行此操作? – 2013-03-18 23:35:13

+0

這是你在找什麼? https://github.com/RestKit/RestKit#centralize-configuration-in-an-object-manager – 2013-03-19 01:05:46

+0

我在看https://github.com/RestKit/RestKit/issues/1286沒有成功。 – 2013-03-19 09:50:56

5

這適用於Restkit 0.21.0:

NSString* jsonFilePath = [[NSBundle mainBundle] pathForResource:@"fileName" 
               ofType:@"json"]; 

NSString* JSONString = [NSString stringWithContentsOfFile:jsonFilePath 
               encoding:NSUTF8StringEncoding 
               error:NULL]; 


NSError* error; 
NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; 
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:RKMIMETypeJSON error:&error]; 
if (parsedData == nil && error) { 
    // Parser error... 
} 

//_objectManager is RKObjectManager instance 
NSMutableDictionary *mappingsDictionary = [[NSMutableDictionary alloc] init]; 
for (RKResponseDescriptor *descriptor in _objectManager.responseDescriptors) { 
    [mappingsDictionary setObject:descriptor.mapping forKey:descriptor.keyPath]; 
} 

RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary]; 
NSError *mappingError = nil; 
BOOL isMapped = [mapper execute:&mappingError]; 
if (isMapped && !mappingError) { 
    NSLog(@"result %@",[mapper mappingResult]); 
} 
5

這適用於Restkit 0.20,使用核心數據實體。它基於@innerself給出的解決方案

NSString* jsonFilePath = [[NSBundle mainBundle] pathForResource:@"info-base" 
                 ofType:@"json"]; 

NSString* JSONString = [NSString stringWithContentsOfFile:jsonFilePath 
               encoding:NSUTF8StringEncoding 
                error:NULL]; 


NSError *error = nil; 

NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; 
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:RKMIMETypeJSON error:&error]; 
if (parsedData == nil && error) { 
    // Parser error... 
    NSLog(@"parse error"); 
} 

//_objectManager is RKObjectManager instance 
NSMutableDictionary *mappingsDictionary = [[NSMutableDictionary alloc] init]; 
for (RKResponseDescriptor *descriptor in [RKObjectManager sharedManager].responseDescriptors) { 

    [mappingsDictionary setObject:descriptor.mapping forKey:descriptor.keyPath]; 
} 

RKManagedObjectMappingOperationDataSource *datasource = [[RKManagedObjectMappingOperationDataSource alloc] 
                 initWithManagedObjectContext:[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext 
                       cache:[RKManagedObjectStore defaultStore].managedObjectCache]; 

RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData 
                  mappingsDictionary:mappingsDictionary]; 
[mapper setMappingOperationDataSource:datasource]; 

NSError *mappingError = nil; 
BOOL isMapped = [mapper execute:&mappingError]; 
if (isMapped && !mappingError) { 
    // data is in [mapper mappingResult] 
} 
1

對於Restkit 0.22,您可以使用此代碼。這將返回一個RKMappingResult,其中您可以使用屬性.array映射後枚舉對象。

- (RKMappingResult *)mapJSONStringWithString:(NSString *)jsonString 
{ 
    RKMappingResult *result = nil; 

    NSError* error; 
    NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; 
    id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:RKMIMETypeJSON error:&error]; 
    if (parsedData == nil && error) { 
     NSLog(@"json mapping error"); 
    } 

    NSDictionary *mappingsDictionary = @{@"":[CustomMappingClass getMappingForUsers]}; 

    ObjectClass *obj = [ObjectClass new]; 
    RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary]; 
    NSError *mappingError = nil; 
    mapper.targetObject = obj; 
    BOOL isMapped = [mapper execute:&mappingError]; 
    if (isMapped && !mappingError) { 
     result = [mapper mappingResult]; 
    } 

    return result; 
} 
2

您可以看到RestKit如何在RKManagedObjectResponseMapperOperation類的內部執行此操作。

這個操作有三個階段。

第一個是將JSON字符串解析爲NSDictionarys,NSArrays等。這是最簡單的部分。

id parsedData = [RKMIMETypeSerialization objectFromData:data 
               MIMEType:RKMIMETypeJSON 
                error:error]; 

接下來,您需要運行映射操作將此數據轉換爲NSManagedObjects。這涉及更多一點。

__block NSError *blockError = nil; 
__block RKMappingResult *mappingResult = nil; 
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; 
operationQueue.maxConcurrentOperationCount = 1; 

[[RKObjectManager sharedManager].managedObjectStore.persistentStoreManagedObjectContext performBlockAndWait:^{ 

請記住用您自己的映射替換此字典。密鑰[NSNull null]映射來自根的這個對象。

NSDictionary *mappings = @{[NSNull null]: [jotOfflineRequestStatus mapping]}; 

    RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData 
                   mappingsDictionary:mappings]; 

    RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc] 
                  initWithManagedObjectContext:[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext 
                  cache:[RKManagedObjectStore defaultStore].managedObjectCache]; 
    dataSource.operationQueue = operationQueue; 
    dataSource.parentOperation = mapper; 
    mapper.mappingOperationDataSource = dataSource; 

    [mapper start]; 
    blockError = mapper.error; 
    mappingResult = mapper.mappingResult; 
}]; 

您現在需要運行已放入我們創建的operationQueue中的任務。在這個階段,與現有NSManagedObjects的連接已經完成。

if ([operationQueue operationCount]) { 
    [operationQueue waitUntilAllOperationsAreFinished]; 
} 
+0

+1!我的實現的關鍵是最後一步,operationQueue.waitUntilAllOperationsAreFinished()。沒有這些,映射過程在完成映射所需關係之前返回我的NSManagedObject。 – davidethell 2015-04-01 10:53:17