2012-01-15 67 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