How to serialize NSManagedObject to JSON in restkit 0.20? - objective-c

How to serialize NSManagedObject to JSON in restkit 0.20 using inverse mapping?
Right now I don't need to post anything anywhere.
I would like manually create object MyObjectManaged.
Set some attributes for example:
id,
name,
age
Map them with existing mapping my mapping to JSON attributes:
userid,
first_name,
age
create and print JSON.
Is it possible? When yes, how?
Thank you in advance for your answer.

I've recently been trying to do the same thing :) I wanted to keep the mappings so that eventually I can hook up to a server, but also reuse them for serializing objects out to a file.
I did this using the inverseMapping and running it through an RKMappingOperation.
First set up your mappings from JSON -> Core Data Object
RKEntityMapping mapping = [RKEntityMapping mappingForEntityForName:#"MyManagedObject" inManagedObjectStore:rkManagedObjectStore];
[self.nodeMapping addAttributeMappingsFromDictionary:#{
#"userid": #"id",
#"first_name": #"name",
#"age": #"age"
}];
Then use the inverse mapping to map your object instance (e.g. "myObject") to a dictionary:
NSMutableDictionary *jsonDict = [NSMutableDictionary dictionary];
RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new];
RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:myObject
destinationObject:jsonDict
mapping:[mapping inverseMapping]];
operation.dataSource = dataSource;
NSError *error = nil;
[operation performMapping:&error];
Assuming there's no error, you can then serialize the dictionary:
NSData *data = [RKMIMETypeSerialization dataFromObject:jsonDict
MIMEType:RKMIMETypeJSON
error:&error];
Not sure what you wanted to do with it from there, but if you wanted to print it to a string you could do:
NSString *jsonString = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding]
Hope that helps

John Martin answer seems to work but I got the problem that NSManagedObject instances with a NSNumber property that is set with
[NSNumber numberWithBool:boolvalue]
serializes a json as value 1/0 instead of true/false.
Our backend could not handle numbers as booleans.
I solved this with using the RestKit built in class: RKObjectParameterization
Using the follow method my NSManagedObjects were properly serialized when there was an NSNumber property that was set as a bool.
+ (NSString *)getJsonObjectWithDescriptor:(RKRequestDescriptor *)requestDescriptor objectToParse:(id)objectToParse {
NSError *error = nil;
NSDictionary *jsonDict = [RKObjectParameterization parametersWithObject:objectToParse requestDescriptor:requestDescriptor error:&error];
NSData *data = [RKMIMETypeSerialization dataFromObject:jsonDict
MIMEType:RKMIMETypeJSON
error:&error];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

You can head over to the RestKit wiki and have a look in the object mapping. In the paragraph "Object Parameterization & Serialization" you'll find the information about the serialization and inverse mapping.

Related

convert NSMutableDictionary to JSON and string

I want to add a json data to HTTPBody request for an iOS app.
I am using objective c.
So I decided to use NSMutableDictionary to convert it to JSON
#property NSMutableDictionary* project;
Parameters:
project (required): a hash of the project attributes, including:
name (required): the project name
identifier (required): the project identifier
description
This is the JSON format when adding data as a raw:
If I want the JSON to look like this, do I have to create NSMutableDictionary object and have another NSMutableDictionary object inside it with the key name #"project"?
{
"project": {
"name": "",
"identifier": "example",
"description": "",
}
}
I tried to have only one NSMutableDictionary
Here is my code:
[self.project setObject:self.projectName.text forKey:#"name"];
[self.project setObject:self.projectDescription.text forKey:#"description"];
[self.project setObject:self.projectIdentifier.text forKey:#"identifier"];
Here is how to convert it to JSON:
NSData *data = [NSJSONSerialization dataWithJSONObject:project options:NSJSONWritingPrettyPrinted error:nil];
NSString* jsonString = [[NSString alloc]initWithData: data
encoding: NSUTF8StringEncoding ];
NSData* anotherdataobj = jsonString;
[request setHTTPBody:anotherdataobj];
I convert it to NSData again because HTTPBody accept NSData for the parameter.
To be clear:
1- do i have to create NSMutableDictionary for project and add NSMutableDictionary projectdetails as a value for for its key #"project"
2- Do I have to convert the string into NSData again to pass it for the HTTPBody?
Correct me if i'm wrong here?
You will definitely need another dictionary inside the first one. Whether you use a mutable version or a literal is up to you.
Note: you probably want to use the newer and much more readable Objective-C syntax.
Option 1:
NSMutableDictionary *object = [NSMutableDictionary dictionary];
NSMutableDictionary *project = [NSMutableDictionary dictionary];
project[#"name"] = whatever;
project[#"identifier"] = whateverElse;
project[#"description"] = stillSomethingElse;
object[#"project"] = project;
Option 2:
NSDictionary *object =
#{
#"project":
#{
#"name": whatever,
#"identifier": whateverElse,
#"description": stillSomethingElse,
}
};
NSJSONSerialization dataWithJSONObject:options:error: already returns an NSData object? Why would you need to convert it again? Also, you certainly don't want to cast an NSData object to an NSString, they're two completely different objects.

Converting a JSON file to NSMutableDictionary in Objective C?

I have a json file that looks like this:
{
"data":
{
"level": [
{
//bunch of stuff
}
]
}
}
Now I want to convert that into a array of levels that I can access. If I take away the {"data: part, then I can use this:
NSData *allLevelsData = [[NSData alloc] initWithContentsOfFile:fileLoc];
NSError *error = nil;
NSMutableDictionary *allLevels = [NSJSONSerialization JSONObjectWithData:allLevelsData options:kNilOptions error:&error];
if(!error){
NSMutableArray *level = allLevels[#"level"];
for (NSMutableDictionary *aLevel in level){
//do stuff with the level...
But I have to have the {"data: as part of the file, and I can't figure out how to get a NSData object out of the existing NSData object. Any ideas?
Don't you need to pull the level NSArray out of the data NSDictionary first?
NSData *allLevelsData = [[NSData alloc] initWithContentsOfFile:fileLoc];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:allLevelsData options:kNilOptions error:&error];
if(!error){
NSArray *levels = dataDictionary[#"data"][#"level"];
for (NSDictionary *aLevel in levels){
//do stuff with the level...
You won't get mutable objects back by default and declaring the variables as mutable doesn't make them so. Take a mutableCopy of the result instead (assuming you really do need mutability).
Why are you trying to prune ahead of time? If you decode the original JSON, you'll be able to extract the level array from the data dict in the decoded dict.
It's not clear what else you're trying to accomplish or why you are going the path you ask about. Note, this doesn't necessarily mean your path is wrong, just that without a clearer indication of what goal you're really trying to accomplish or what you've actually tried (and errored/failed, along with how it failed), you're likely only to get vague/general answers like this.

RestKit: mapping BOOL and integer values

I'm evaluating RestKit to use in my project. I've created a simple app that loads some JSON and maps it into Objective-C objects. I'm having a problem correctly mapping a JSON object that has numeric and logical fields. E.g.
{
"integerValue":"5",
"booleanValue":"YES",
}
I want these to map to the following properties in my data object:
#property int integerValue;
#property BOOL booleanValue;
It didn't work out of the box, so I've created a value transformer for that:
[_activityMapping setValueTransformer:[RKBlockValueTransformer valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class inputValueClass, __unsafe_unretained Class outputValueClass) {
if([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSNumber class]]) {
return YES;
}
else {
return NO;
}
} transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputClass, NSError *__autoreleasing *error) {
if([[inputValue class] isSubclassOfClass:[NSString class]] && [outputClass isSubclassOfClass:[NSNumber class]]) {
NSString *inputString = (NSString *)inputValue;
if([inputString isEqualToString:#"YES"] || [inputString isEqualToString:#"NO"]) {
*outputValue = [NSNumber numberWithBool:[inputString boolValue]];
}
else {
*outputValue = [NSNumber numberWithInt:[inputString intValue]];
}
}
else {
*outputValue = [inputValue copy];
}
return YES;
}]];
This code works, but looks ugly. Note how I have to check the input value to see if it's a boolean or an integer. Any suggestions on an elegant solution to this problem?
Please note that I'm using RestKit. I do know about NSJSONSerialization and know how to parse JSON in code. If you suggest a non-RestKit solution, please explain why do you not recommend using RestKit.
The issue is not occurring at the RestKit level but at the JSON level itself.
According to the JSON spec Boolean values should be represented with true/false not YES/NO. If you update your JSON to be semantically correct then RestKit should do the right thing.
Ok. So according to my understanding of your answer, your main problem lies in mapping the data in the JSON object to their very own designated variables.
So, I'd recommend using the conventional NSJSONSerialization approach.
So, first up. You need to store your JSON object in an NSData object. Now, you're most likely downloading the data from a simple URL. So, this is what you'd do :
//This part is just to download the data. If you're using another method - that's fine. Just make sure that the download is in NSData format
NSURL *url = [[NSURL alloc] initWithString : #"YOUR_URL_HERE"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL : url];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:nil];
Now, you need to map those to the NSDictionary... Here's how :
//This is the actual NSJSONSerialization part.
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableLeaves
error:nil];
Now, just map the values to your designated properties.
_integerValue = (int)[jsonDict objectForKey:#"integerValue"];
_booleanValue = (BOOL)[jsonDict objectForKey:#"booleanValue"];

How to convert json string to nsdictionary on json parser framework on objective c

I am trying to convert raw json string to NSDictionary. but on NSDictionary i got different order of objects as on json string but i need exactly same order in NSDictionary as on json string. following is code i have used to convert json string
SBJSON *objJson = [[SBJSON alloc] init];
NSError *error = nil;
NSDictionary *dictResults = [objJson objectWithString:jsonString error:&error];
From NSDictionary's class reference:
The order of the keys is not defined.
So, basically you can't do this when using a standard NSDictionary.
However, this may be a good reason for subclassing NSDictionary itself. See this question about the details.
NSDictionary is an associative array and does not preserve order of it's elements. If you know all your keys, then you can create some array, that holds all keys in correct order (you can also pass it with your JSON as an additional parameter). Example:
NSArray* ordered_keys = [NSArray arrayWithObjects: #"key1", #"key2", #"key3", .., nil];
for(NSString* key is ordered_keys) {
NSLog(#"%#", [json_dict valueForKey: key]);
}
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray* latestLoans = [json objectForKey:#"loans"]; //2
NSLog(#"loans: %#", latestLoans); //3
Source: Follow this link http://www.raywenderlich.com/5492/working-with-json-in-ios-5
Good tutorial but works only on iOS5

Can I minimize the number of objects used in this SBjson code?

The response I receive from the server is formatted as such:
{
"Data":{
"Key": "Value"
...
},
"Key": "Value"
...
}
However, I am only interested in the elements under "Data".
Here is the code I'm currently using:
SBJsonParser *parser = [SBJsonParser new];
NSString *responseString = [request responseString];
NSDictionary *responseData = [parser objectWithString:responseString];
NSString *infoString = [responseData objectForKey:#"Data"];
NSDictionary *infoData = [parser objectWithString:infoString];
Is there a way to perform the same thing without explicitly declaring 5 objects? Just looking for some sense of short-hand that I should be using.
Your last two lines are wrong - "Data" is actually an NSDictionary, so you don't need to double parse it.
Also, most objective-C programmers would nest calls where they know that the returns are safe - by which I mean don't need additional checking. For instance, this would see a more natural implementation to me:
NSDictionary *responseDictionary = [[request responseString] JSONValue];
NSDictionary *infoData = [responseDictionary objectForKey:#"Data"];
Note that I am using the convenience method JSONValue from the category on NSObject that comes with SBJSON.