通过RestKit将本地NSString的JSON反序列化为对象(无需网络下载)

发布于 2024-12-27 15:23:45 字数 504 浏览 0 评论 0原文

是否可以通过 RestKit 将 JSON 的 NSString 反序列化为对象?我在此处检查了 API 列表,但找不到可用于此目的的内容。我能找到的最接近的是解析输入后返回 NSDictionary 的各种解析器类。我假设 RestKit 在下载响应后使用这些解析器,所以我的想法是该功能在 RestKit 中的某个地方可用,但没有公开公开。

如果我没有遗漏任何东西并且没有公开此功能,那么替代方案是什么?两个明显的看起来不太有希望:获取结果 NSDictionary 并尝试反序列化自己(有效地重新实现 RestKit)或尝试深入研究 RestKit 源代码并查看是否可以以某种方式暴露(看起来乏味且错误)易于)。

预先感谢您的任何帮助。

PS:这个想法是,反序列化对象上的字符串属性实际上是另一组对象的 JSON 表示(某种意义上是嵌入式 JSON),并且在运行时根据需要进行反序列化。

Is it possible to deserialize an NSString of JSON into objects via RestKit? I checked the API list here and could not find something that would serve for this purpose. The closest I could find are the various parser classes that return NSDictionary after parsing the input. I assume RestKit uses these parsers after downloading the response so my thinking is that the functionality is available somewhere in RestKit but not exposed publicly.

If I am not missing anything and this functionality is not exposed, what would be the alternatives? Two obvious ones do not look very promising: Get the resulting NSDictionary and try to deserialize myself (effectively reimplementing RestKit) or try to dive into RestKit source and see if this can be somehow exposed (looks tedious and error prone).

Thanks in advance for any help.

PS: The idea is that a string property on a deserialized object is actually the JSON representation of another set of objects (embedded JSON in a sense) and it is deserialized on demand during runtime.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

浅紫色的梦幻 2025-01-03 15:23:45

相当“简单”:

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

Pretty "simple":

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]);
从﹋此江山别 2025-01-03 15:23:45

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);
}

As of 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);
}
疯狂的代价 2025-01-03 15:23:45

这适用于 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]);
}

This works for 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]);
}
你的他你的她 2025-01-03 15:23:45

这适用于 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]
}

This works for Restkit 0.20, using Core Data Entities. It is based in the solution given by @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]
}
弥繁 2025-01-03 15:23:45

您可以在 RKManagedObjectResponseMapperOperation 类中了解 RestKit 如何在内部执行此操作。

此操作分为三个阶段。

首先是将 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;
}];

您现在需要运行已放入我们创建的操作队列中的任务。正是在这个阶段,建立了与现有 NSManagedObject 的连接。

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

You can see how RestKit does this internally in the RKManagedObjectResponseMapperOperation class.

There are three stages of this operation.

The first is to parse the JSON string into NSDictionarys, NSArrays, etc. This is the easiest part.

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

Next you need to run a mapping operation to convert this data into your NSManagedObjects. This is a bit more involved.

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

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

Remember to replace this dictionary with your own mappings. The key [NSNull null] maps this object from the root.

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

You now need to run the tasks that have been put into the operationQueue we created. It is at this stage that connections to existing NSManagedObjects are made.

if ([operationQueue operationCount]) {
    [operationQueue waitUntilAllOperationsAreFinished];
}
野侃 2025-01-03 15:23:45

一个更面向 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);
}

A more iOS 5+ oriented answer:

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);
}
野生奥特曼 2025-01-03 15:23:45

对于 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;
}

For Restkit 0.22, You can use this code. This returns an RKMappingResult wherein you can enumerate the objects after mapping using the property .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;
}
二手情话 2025-01-03 15:23:45

从没有任何答案的观点来看,RestKit 中似乎还不存在这个功能。我没有花更多时间尝试弄清楚如何进行映射,而是使用 JsonKit 解析器的输出编写了自己的映射器,并删除了对 RestKit 的依赖(使用内置类进行网络活动)。现在我的映射器不是通用的(它对对象的布局方式及其在 json 中的名称有一些依赖),但它适用于项目的目的。我可能会稍后回来并将其变成一个更通用的对象映射库。

编辑:这是选定的答案,因为截至此答案的日期(2012 年 1 月 21 日)没有其他答案。从那时起,我就停止了 iOS 的工作,再也没有访问过这个问题。现在我选择 Ludovic 的答案是因为另一位用户的评论和对该答案的赞同。

Judging by the views without any answers, it seems this facility does not exist in RestKit yet. Instead of spending more time trying to figure out how to do the mapping, I wrote my own mapper using the output of JsonKit parser and removed the dependency on RestKit (used the builtin classes for network activity). Right now my mapper is not generic (it has a few dependencies on how the objects are laid out and their names in json) but it works for the purposes of the project. I might come back later and turn it into a more generic object mapping library later on.

EDIT: This was selected answer because there was no other answer as of this answer's date (Jan 21, 2012). Since then, I stopped working on iOS and never visited this question again. Now I am selecting Ludovic's answer because of another user's comment and the upvotes for that answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文