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

     2023-02-23     84

关键词:

【中文标题】通过 RestKit 将 JSON 的本地 NSString 反序列化为对象(无网络下载)【英文标题】:Deserializing local NSString of JSON into objects via RestKit (no network download) 【发布时间】:2012-01-15 21:42:47 【问题描述】:

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

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

提前感谢您的帮助。

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

【问题讨论】:

【参考方案1】:

相当“简单”:

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

【讨论】:

【参考方案2】:

截至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);

【讨论】:

您知道如何从已配置的 RKObjectManager 中执行此操作吗? 这是您要找的吗? github.com/RestKit/…【参考方案3】:

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

您可以在 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;
];

您现在需要运行已放入我们创建的 operationQueue 的任务。正是在这个阶段建立了与现有 NSManagedObjects 的连接。

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

【讨论】:

+1!我实现的关键是您的最后一步, operationQueue.waitUntilAllOperationsAreFinished()。没有它,映射过程在完成映射所需关系之前返回我的 NSManagedObject。 这对我有用。你如何让 RestKit 将对象存储回 Core Data?我试过 [[RKObjectManager sharedManager].managedObjectStore.persistentStoreManagedObjectContext saveToPersistentStore:&error];在mappingResult = mapper.mappingResult之后;但这没有帮助。有什么建议吗?【参考方案6】:

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

【讨论】:

【参考方案7】:

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

【讨论】:

【参考方案8】:

这不是您要找的吗? http://restkit.org/api/0.10.0/Classes/RKJSONParserJSONKit.html

【讨论】:

我知道这些解析器类。他们将字符串解析为NSDictionary,这是整个反序列化过程的第一部分。我需要接受字符串并输出映射对象的功能。换句话说,在 RestKit 依次完成的三件事中(下载响应、解析下载的字符串、映射对象),我需要只做最后两件事的事情。 嘿,我也遇到了同样的问题。我有一些 JSON 需要映射到我的模型(NSManagedObject)。你找到解决办法了吗? @MikeBevz:我编写了自己的映射器。 :-) 我写了更多细节来回答这个问题。【参考方案9】:

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

编辑:这是选择的答案,因为截至该答案的日期(2012 年 1 月 21 日)没有其他答案。从那以后,我停止了在 iOS 上的工作,并且再也没有访问过这个问题。现在我选择 Ludovic 的答案是因为另一个用户的评论和对该答案的支持。

【讨论】:

为什么选择这个答案? Ludovic 的解决方案效果很好! @Kyle:这是选择的答案,因为截至该答案的日期(2012 年 1 月 21 日)没有其他答案。从那以后,我停止了在 iOS 上的工作,并且再也没有访问过这个问题。尽管我目前无法亲自验证答案,但由于您的评论,我选择了 Ludovic 的答案。

RestKit - 将数据库与本地 JSON 文件同步

】RestKit-将数据库与本地JSON文件同步【英文标题】:RestKit-SyncDataBasewithlocalJSONfile【发布时间】:2014-10-2421:55:32【问题描述】:我提供了一个示例JSON文件(出于测试目的,我没有提前访问Web服务)。加载文件并转换为NSDictionary后... 查看详情

RestKit 无法将 JSON 请求中格式为字符串的日期保存到我的本地数据库

】RestKit无法将JSON请求中格式为字符串的日期保存到我的本地数据库【英文标题】:RestKitcan\'tsavedatesthatareformattedasstringsinJSON-requesttomylocaldatabase【发布时间】:2012-06-2118:33:02【问题描述】:我正在使用RestKit将JSON同步到本地数据... 查看详情

如何使用带有 RKObjectMapping 的 RestKit 0.24 将本地 JSON 字符串映射到对象?

】如何使用带有RKObjectMapping的RestKit0.24将本地JSON字符串映射到对象?【英文标题】:HowtomapalocalJSONstringintoanobjectusingRestKit0.24withRKObjectMapping?【发布时间】:2015-11-2114:59:52【问题描述】:我正在尝试使用RestKit0.24.0将JSONNSString映射... 查看详情

将 UIImage 发送到仅接受 JSON 的 Web 服务(通过 RestKit)

】将UIImage发送到仅接受JSON的Web服务(通过RestKit)【英文标题】:SendinganUIImagetoawebservicethatonlyacceptsJSON(viaRestKit)【发布时间】:2012-04-2615:39:47【问题描述】:我无法将UIImage对象发送到我的RESTWeb服务只接受JSON作为输入。我已经设... 查看详情

iOS RestKit 0.2 解析本地 Json 的最佳方法是啥

】iOSRestKit0.2解析本地Json的最佳方法是啥【英文标题】:iOSRestKit0.2WhatisthebestwaytoparselocalJsoniOSRestKit0.2解析本地Json的最佳方法是什么【发布时间】:2014-03-2710:57:43【问题描述】:我阅读了许多关于通过Http请求解析json的文章,但几... 查看详情

JSONKit(在 RestKit 中)将 JSON 转换为 NSArray

】JSONKit(在RestKit中)将JSON转换为NSArray【英文标题】:JSONKit(inRestKit)convertingJSONintoNSArray【发布时间】:2011-08-2119:47:22【问题描述】:我正在使用RestKit处理HTTP请求,并且通过一些请求,我得到一些总线的JSON响应:["bus_number":"1","... 查看详情

RestKit 0.20.1 映射本地 JSON “此类不符合键值编码...”

】RestKit0.20.1映射本地JSON“此类不符合键值编码...”【英文标题】:RestKit0.20.1mappinglocalJSON"thisclassisnotkeyvaluecoding-compliantforthekey..."【发布时间】:2013-05-2700:00:28【问题描述】:嗨,我正在使用RestKit来映射我已经收到(我... 查看详情

RestKit“无法在没有数据源的情况下执行关系映射”来自本地 JSON 文件

】RestKit“无法在没有数据源的情况下执行关系映射”来自本地JSON文件【英文标题】:RestKit"Cannotperformrelationshipmappingwithoutadatasource"fromlocalJSONfile【发布时间】:2013-09-1114:28:01【问题描述】:(更完整的代码见我的要点:ht... 查看详情

将 RestKit 与本地服务器一起使用

】将RestKit与本地服务器一起使用【英文标题】:UsingRestKitwithlocalserver【发布时间】:2012-05-1702:44:39【问题描述】:我的iPhone应用程序中有RestKit与Heroku上的Rails应用程序交互,但RestKit似乎无法与我机器上本地运行的Rails应用程序... 查看详情

如何通过 iOS 6 中的 RESTkit 2.0 将 JSON 中的 base64 图像导入核心数据二进制文件?

】如何通过iOS6中的RESTkit2.0将JSON中的base64图像导入核心数据二进制文件?【英文标题】:HowcanIimportbase64imageinJSONintocoredatabinaryviaRESTkit2.0iniOS6?【发布时间】:2013-06-0612:47:34【问题描述】:我一直在使用RKManagedObjectImporter中的importOb... 查看详情

RestKit本地删除对象,依然出现在mapping中

】RestKit本地删除对象,依然出现在mapping中【英文标题】:RestKitlocaldeletionofobjects,stillappearsinmapping【发布时间】:2014-03-2708:30:40【问题描述】:我正在为我的应用程序使用RestKit0.20.3。它具有离线模式,所以我必须将对象存储在本... 查看详情

Restkit:multipartFormRequestWithObject 不是 json

】Restkit:multipartFormRequestWithObject不是json【英文标题】:Restkit:multipartFormRequestWithObjectnotjson【发布时间】:2013-10-2308:48:00【问题描述】:我正在使用RestKit2.0通过“multipartFormRequestWithObject”方法将核心数据实体和图像发送到服务器... 查看详情

带有本地 XML 的 RestKit

】带有本地XML的RestKit【英文标题】:RestKitwithlocalXML【发布时间】:2012-09-1707:17:51【问题描述】:我使用RestKit从资源加载XML数据。这很完美,但现在我想改变我的整个程序来读取本地XML文件。我发现可以读取本地xml文件并通过Goo... 查看详情

RESTKit 将 nil 序列化为 JSON

】RESTKit将nil序列化为JSON【英文标题】:RESTKitserializingniltoJSON【发布时间】:2014-01-1315:11:59【问题描述】:我是RESTKit0.20的新手,但我想知道,现在是否可以将对象的nil实例变量序列化为JSON?确切地说,我想序列化为nil的NSString... 查看详情

RESTKit:在覆盖之前将 GET 对象与本地持久化的对象进行比较

】RESTKit:在覆盖之前将GET对象与本地持久化的对象进行比较【英文标题】:RESTKit:ComparingGETobjectwithlocallypersistedbeforeoverwriting【发布时间】:2014-04-2904:02:41【问题描述】:我在CoreData中有一个保存的对象(持久化)。让我们说下面... 查看详情

使用 JSON 字符串将使用 RestKit 的对象手动加载到核心数据中

】使用JSON字符串将使用RestKit的对象手动加载到核心数据中【英文标题】:ManuallyloadobjectsusingRestKitintoCoreDatausingJSONstring【发布时间】:2012-10-0906:00:12【问题描述】:使用restkit(0.20)的开发分支,有没有办法将JSON字符串映射到核... 查看详情

通过 ID 数组映射 RestKit 中的关系不起作用

】通过ID数组映射RestKit中的关系不起作用【英文标题】:MappingrelationshipsinRestKitthroughanarrayofIDsdoesn\'twork【发布时间】:2012-10-2417:03:51【问题描述】:我正在尝试通过RestKit将用户和组映射到CoreData对象,保持两者之间的关系。用户... 查看详情

Restkit:来自 JSON parentId 的映射关系

】Restkit:来自JSONparentId的映射关系【英文标题】:Restkit:MaprelationshipfromJSONparentId【发布时间】:2014-05-2014:56:44【问题描述】:我将如何设法将以下JSON与Restkit进行映射?以下JSON包含ParentId(ParentMenu)和MenuId,我想使用它们来映射来... 查看详情