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