YAJL - JSON on iOS/iPhone - iphone

In my iPhone app, I am trying to use the JSON library (YAJL) to create a JSON string that looks like the following format:
{"user":
{"name":"Jon", "username":"jon22", "password":"passw#rd", "email":"jon22#example.com"}
}
But I can't figure out the YAJL methods to create this.
I have tried the following:
NSArray *params = [NSArray arrayWithObjects:#"Jon", #"jon22", #"passw#rd", #"jon22#gmail.com", nil];
NSArray *keys = [NSArray arrayWithObjects:#"name", #"username", #"password", #"email", nil];
NSDictionary *userDictionary = [NSDictionary dictionaryWithObjects:params forKeys:keys];
NSString *JSONString = [userDictionary yajl_JSONString];
However, the returned string is not wrapped in the outside "user".
How can I use YAJL to create this json string? Does anyone have experience with this???
Many thanks,
Brett

I don't use YAJL, but SBJSON, which is the one Apple uses in iOS too...
Anyway, the library is behaving correctly: you're not creating an "user" dictionary!
You need to do something like:
NSDictionary *serialize = [NSDictionary dictionaryWithObject:userDictionary forKey:#"user"];
And then "JSON-ize" this one.
This is because when you call -yajl_JSONString on userDictionary, you are using userDictionary as your "root object". If you want to wrap this inside another dictionary, you need to explicitly do so.

I highly recommend that you check out JSONKit https://github.com/johnezang/JSONKit I have used numerous JSON parsers and have found it to be the easiest.
Also the documentation is awesome.

Related

Setting value for nsmutabledictionary in multi levels

I am trying to set a key for UserName as with respect to this code:
{
"CustomerAccount":{
"UserName":"String content"
};
I am trying to set the username here, does anyone know how can I set a name in dictionary with levels?
My code is as:
[mutabledictionary setObject:self.uitextfield.text forKey:UserName];
however this sets the username below to CustomerAccount not insider CustomerAccount.
Any help here would be appreciated.
Thanks.
If the two level mutable dictionary already exists (its not clear from your question) you need to send your setObject:forKey message to the second level dictionary, like so:
[[mutabledictionary objectForKey:#"CustomerAccount"] setObject:self.uitextfield.text forKey:UserName];
You can just add a sub-dictionary, like this:
NSDictionary *userAccount = [NSDictionary dictionaryWithObject:#"String Content" forKey:#"UserName"];
NSMutableArray *accounts = [NSMutableArray arrayWithObject:userAccount];
// do something with accounts
NSLog(#"%#", accounts);
Just create create array of CustomerAccount and use in NSDictionary. Use
[NSDictionary dictionaryWithObjects:objects forKeys:keys];

Match String to ABPropertyID

I'm working now with the AddressBook and I need to convert(match) the String representation of ABPropertyID to ABPropertyID:
#"kABPersonEmailProperty" -> ABPropertyID kABPersonEmailProperty;
Can I do it flexible without using ifs?
Can I do it flexible without using ifs?
Not really. The easiest way is probably to manually prepare an NSDictionary in code that maps between the two. There is no way to do this entirely automatically because the names of the constants are not part of the compiled program.
Example:
NSDictionary *mapping = [NSDictionary dictionaryWithObjectsAndKeys:
#"kABPersonEmailProperty", [NSNumber numberWithInteger:kABPersonEmailProperty],
#"kABPersonEmailProperty", [NSNumber numberWithInteger:kABPersonBirthdayProperty],
nil];

JSON Sort String

framework.
Hi I'm using json-framework.
How to get sorted string when using JSONRepresentation method?
Here is my code:
NSMutableDictionary *tUserIDParam = [NSMutableDictionary dictionary];
[tUserIDParam setObject:#"UserID" forKey:#"#key"];
[tUserIDParam setObject:#"string" forKey:#"#type"];
[tUserIDParam setObject:#"mark" forKey:#"#text"];
NSMutableDictionary *tPasswordParam = [NSMutableDictionary dictionary];
[tPasswordParam setObject:#"Password" forKey:#"#key"];
[tPasswordParam setObject:#"string" forKey:#"#type"];
[tPasswordParam setObject:#"123456" forKey:#"#text"];
NSArray *tParams = [NSArray arrayWithObjects:tUserIDParam,tPasswordParam, nil];
NSDictionary *tParam = [NSDictionary dictionaryWithObject:tParams forKey:#"param"];
NSMutableDictionary *tRequests = [NSMutableDictionary dictionary];
[tRequests setObject:[NSNull null] forKey:#"key"];
[tRequests setObject:[NSNull null] forKey:#"basic"];
[tRequests setObject:tParam forKey:#"conditions"];
NSDictionary *tRequest = [NSDictionary dictionaryWithObject:tRequests forKey:#"request"];
NSString *tJSONStrFromDict = [tRequest JSONRepresentation];
I want to get JSON string like:
{"request":{"key":null,"basic":null,"conditions":{"param":[{"#key":"UserID","#type":"string","#text":"mark"},{"#key":"Password","#type":"string","#text":"123456"}]}}}
But I got this string from above code:
{"request":{"basic":null,"conditions":
{"param":[{"#text":"mark","#key":"UserID","#type":"string"},{"#text":"123456","#key":"Password","#type":"string"}]},"key":null}}
I try to use SBJSONWriter sortKeys property,it does not work...
Have any way to solve my problem?
Thanks!
NSMutableDictionary instance do not preserve the order of elements, neither in alphabeticallz order nor in the order they were inserted. This is independent of JSON.
Furthermore, JSON's data model for object doesn't guarantee order either. If you want a certain order, you'll have to use JSON arrays for the ordered parts.
BTW.: The effect of SBJSONWriter sortKeys is to output the object elements (or properties) alphabetically sorted by the key name. This is what you get.

Iphone:how to create json in Objective c

I am working on iPhone App.I have to return json string to a webservice in following format from Iphone.I am using Objective-C
{
"InspectionDetails":
[
{"isCompleted":"Y","QMSStepId":"1A","QMSEmpId":"6","QMSInspectionID":"1","InspectedDate":"07/28/11 09:52:34", "isNewRoom":"1","RoomInspID":"1","QMSRoomId":"1","QMSScoreId":"4"},
{"isCompleted":"Y","QMSStepId":"1B","QMSEmpId":"4","QMSInspectionID":"1","InspectedDate":"07/28/11 09:52:34", "isNewRoom":"1","RoomInspID":"1","QMSRoomId":"1","QMSScoreId":"3"}
],
"InspectionComments":
[
{"QMSPredefinedCommentId":"1","customText":"Test1 Comment","RoomInspID":"1"},
{"QMSPredefinedCommentId":"2","customText":"Test2 Comment","RoomInspID":"1"}
],
"Tools":
[
{"Facility_Code" : "1","HddId" : "AIPH01"}
]
}
can any one please help me how can I form the above response?
I have an idea that I can do this by using NSArray and NSDictonary but I want all the arrays in one dictionary. Can anyone please guide?
Thanks,
Shradha
The easiest way is to use something like SBJSON. Then you can just do
NSString *jsonString = [myDictionary JSONRepresentation];
I recommend using JSONKit (https://github.com/johnezang/JSONKit), it works very well and is speedy enough to serve common needs.
Suppose you have a NSDictionary like:
NSDictionary *dict = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects:,#"anotherDict",#"anotherDict1",#"anotherDict" nil]
forKeys:[NSArray arrayWithObjects:#"Key1",#"Key2",#"Key3", nil]];
then you can simply get your JSON representation as follows: NSString *jsonString = [dict JSONString].
Read the documentation to get additional features.

Parse JSON collection from Rails in Objective-C on iPhone

I'm using TouchJSON to parse the output of a JSON Rails API, but am having difficulties. The overall goal is to loop through the response, parse the JSON, create a Round instance for each JSON object, and stick those Round objects into an NSArray so I can load this into a UITableView. So if there's a more straight-forward way to do that than what I'm about to show (which currently is NOT working, btw) please let me know.
The Rails API is returning a collection that looks something like this:
[
{
"round": { "course_title": "Title A", "result": "+8" }
},
{
"round": { "course_title": "Title B", "result": "+4" }
},
...
]
I'm also using ASIHTTPRequest and I can successfully get the response using:
NSString *responseString = [request responseString];
But from there, I cannot seem to get anywhere. Here's more-or-less what TouchJSON suggests:
NSString *jsonString = [request responseString]; // [{"round":{...}}, ..., {"round:{...}}]
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSDictionary *dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:nil];
// then I do this...
NSLog(#"JSON: %#", dictionary); // JSON: null
I thought from there I would be able to loop through the dictionary and create the object mappings using my Round class. But maybe that's the wrong approach altogether.
My thoughts are that the JSON being returned from Rails is an array of JSON objects, so maybe that's why the JSON parser doesn't recognize it as valid JSON? From this, I have two questions:
1) Should TouchJSON be able to accept an array of JSON objects like what my API is returning?
2) Is it possible to cast the responseString to an NSArray so I can loop through each "round" and parse the JSON that way? If I remove the first and last characters from the response string (i.e. "[" and "]") the JSON parser will only grab the first "round" in the collection.
3) Am I going about this whole process correctly?
Any tips/advice would be much appreciated.
TouchJSON presents three main ways to go from JSON to an Obj-C object. They are all present in the header for CJSONDeserializer which you're already using:
- (id)deserialize:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError;
The first one will return return whatever, either a dictionary, array, string or whatever the root type of the JSON is.
The other two expect a dictionary or an array and will complain (i.e. return nil and give you an NSError) if they don't get the right data.
The deserializeAsDictionary:error: method of CJSONDeserializer relies on the scanJSONDictionary:error: method of CJSONScanner. This method expects the "dictionary" to be an object literal. Therefore, your data must start with a {. Since your data is an array, you would want to use the deserializeAsArray:error: method of CJSONDeserializer.
Read the documentation carefully, your code is incorrect. It should look like this:
NSData *jsonData = [request responseData]
NSArray *rounds = [[CJSONDeserializer deserializer] deserialize:jsonData error:nil];
// then I do this...
NSLog(#"JSON: %#", rounds);
You could also have used:
NSArray *rounds = [[CJSONDeserializer deserializer] deserializeAsArray:jsonData error:nil];
However your absolute BIGGEST mistake was passing nil for error. You could have avoided going to stackoverflow at ALL if you had passed something in for NSError and then checked that.
With the right tools, this is WAY simpler than you're making it. I do this sort of thing all the time.
Use Stig's JSON framework, and import the NSString category that provides the JSONValue method.
Then inside your ASIHTTPRequest response handler code, go thusly:
NSMutableArray *roundlist = [NSMutableArray array];
NSArray *results = [[request responseString] JSONValue];
for (NSDictionary *item in results) {
Round *myRound = [item objectForKey:#"round"];
//don't actually do the above. Do whatever you do to instantiate a 'Round'.
[roundlist addObject:myRound];
}
[self.tableView reloadData];
EDIT: Geezo. Objection noted re valueForKey: vs objectForKey:. I updated my code sample, and I think we all learned something here.
I also didn't mean any offense with the phrase "with the right tools". OP was looking to simplify his code, and the RIGHT TOOL for that is the library with the simplest interface. I have nothing against TouchJSON per se, but JSON Framework has the simpler interface.