Objective - C : How to read json? [duplicate] - objective-c

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to parse JSON in Objective-C?
I totally new with Objective c, I need to value of distance from google distance matrix json, but data that I can get from json just the first element,
so How to get value in distance this json?
{
"destination_addresses": [
"San Francisco, Californie, États-Unis",
"Victoria, BC, Canada"
],
"origin_addresses": [
"Vancouver, BC, Canada",
"Seattle, État de Washington, États-Unis"
],
"rows": [
{
"elements": [
{
"distance": {
"text": "1 732 km",
"value": 1732128
},
"duration": {
"text": "3 jours 23 heures",
"value": 340902
},
"status": "OK"
}
]
}
],
"status": "OK"
}
ok here is my sample code that just follow from JSON Tutorial :
I already use SBJSON , but I can only rows key, so how to get value in Distance key?
SBJSON *parser = [[SBJSON alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
URLWithString:#"http://maps.googleapis.com/maps/api/distancematrix/json?origins=Vancouver+BC|Seattle&destinations=San+Francisco|Victoria+BC&mode=bicycling&language=fr-FR&sensor=false"]];
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *statuses = [parser objectWithString:json_string error:nil];
for (NSDictionary *status in statuses)
{
NSLog(#"%# - %#", [status objectForKey:#"rows"]);
}

If you're targeting iOS 5 or OS X v10.7 then you can just use Apple's own NSJSONSerialization. You probably particularly want +JSONObjectWithData:options:error:. Using the built-in stuff is always preferable to third-party options because it eliminates the problem that the third party has no direct interest in fixing its bugs and no way to supply fixes for your application without your intervention.
If you want to support older devices then you probably want to import SBJSON — as as Rengers suggests — or any of the hundred others. For the reasons above I highly recommend you fall back on those only if NSJSONSerialization isn't available.
EDIT: it appears you already have SBJSON in place and are asking about how to traverse the results? From reading the JSON:
the root object will be a dictionary
within it, rows will be an array of dictionaries
each dictionary has an array named elements
each entry in that array is a dictionary
within that, distance is another dictionary
distance contains two strings, with keys "text" and "value"
So if you weren't to do any validation at all, to get to the distance dictionary you might do:
NSDictionary *result = [parser objectWithString:...];
NSLog(#"distance dictionary is: %#"
[[[[[
result objectForKey:#"rows"]
objectAtIndex:0]
objectForKey:#"elements"]
objectAtIndex:0]
objectForKey:#"distance"]
);
Based on your sample code, it looks like you may actually be getting an array of the sorts of dictionary posted rather than the dictionary directly. Obviously adapt if that's the case.

You need to use a JSON parser like SBJSON. This will create a NSDictionary/NSArray with all the values and keys. Then use the normal dictionary and array methods to access the data.

Related

iOS and JSON nesting issue

I am working on an app for a game server company and part of the app requires the user to see a list of his or her game servers and whether or not they are online, offline, how many players on them, the server name, etc. This data is all found in a JSON file hosted on the web updated from a MySQL database.
Using the code below, I can't seem to get it working. Now, please understand it is one of my first times working with JSON and have no choice as this is what the client requested. I talked to my partner but he couldn't seem to debug the issue himself.
The error I get is something like:
No visible #interface for 'NSArray' declares the selector 'objectForKey:'
I've tried several versions of the code, all with no success.
It would be much appreciated if you could please help me debug this code and get it working along with the commented out section near the bottom updating the TableViewCells with the server name, players online, and status (0=offline, 1=online, 2=busy, 3=suspended, -1=unable to start).
Please note that the format of the JSON file must remain as is and is only possible to make very minor changes.
Thank you,
Michael S.
My header file:
http://pastebin.com/EkuwVSmY
My main file:
http://pastebin.com/09Ju0uDu
My JSON file:
{
"status": "OK",
"error": "",
"debug": "2 server(s)",
"result": {
"servers": [
{
"id": 1,
"title": "Test",
"players": 0,
"slots": 10,
"status": 3
},
{
"id": 2,
"title": "Creative Spawn",
"players": 0,
"slots": 5,
"status": -1
}
]
}
}
The block that gives me the error is:
NSArray *serverResults = [[news objectForKey:#"result"] objectForKey:#"servers"];
if ([[[serverResults objectAtIndex:indexPath.row] objectForKey:#"status"] isEqual:#"1"]) {
serverPlayers.text = #"10000000";
}
The error you get points out that you are working on an NSArray instead of a NSDictionary. There is no method objectForKey defined on an NSArray. So what you could do is to debug your Webservice response and check the Data types.
Regarding at your output from JSON it should be like that:
NSDictionary (Keys: status, error, debug, result, servers)
servers is an NSArray which has NSDictionaries as elements.
To get the title of a server:
NSDictionary *resultDict = [news objectForKey:#"result"];
NSArray *servers = [resultDict objectForKey:#"servers"];
NSDictionary *firstServer = [servers objectAtIndex:0]; // I fetch here the first server
NSString *titleOfFirstServer = [firstServer objectForKey:#"title"];
NSNumber *statusOfFirstServer = [NSNumber numberWithInt:[[firstServer objectForKey:#"status"] intValue];
To iterate over all servers you should do it like that:
NSDictionary *resultDict = [news objectForKey:#"result"];
NSArray *servers = [resultDict objectForKey:#"servers"];
for(NSDictionary *server in servers) {
NSString *title = [server objectForKey:#"title"];
NSNumber *status = [NSNumber numberWithInt:[[server objectForKey:#"status"] intValue];
NSLog(#"%#%d", title, [status intValue]);
}

Cocoa Touch JSON Handling

I've been looking for a while now and I can't seem to find a solution.
I am trying to format a JSON object that is being held in an NSData *receivedData.
The format of the JSON is:
[
{
"name":"Stephen",
"nickname":"Bob"
},
{
"name":"Rob",
"nickname":"Mike"
},
{
"name":"Arya",
"nickname":"Jane"
}
]
Normally I would use "NSJSONSerialization JSONObjectWithData:" of the NSDictionary. Then I would normally take the root of the JSON (in this case it would be something like "People":) and create the array from that root object. However as you can see this response is simply an array without a root object. I'm not sure how to handle this. The end goal is to have an array of Person objects, populated with the data in the JSON.
Edit: I would also like to add that I want to keep it native without third party libraries.
OK for anyone reading this. I just figured it out. Instead of formatting the initial NSData into a dictionary, you put that straight into an array. Then create a dictionary for each object in the array. Like so:
NSArray *response = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
NSDictionary* json = [responseArray objectAtIndex:0];
NSLog (#"%#",[json objectForKey:#"nickname"]);

Working with fetched request sort descriptors

I have problem with my sort descriptor. I am fetching a ranking of a football club. This is how my webservice gives the data back.
"ranking": [
{
"type": "competitie",
"position": "1",
"name": "Club Brugge",
"gamesPlayed": "10",
"gamesWon": "6",
"gamesTied": "4",
"gamesLost": "0",
"goalsPos": "25",
"goalsNeg": "12",
"goalsDiff": 13,
"points": "22"
}
Here is my fetch request.
- (void)getKlassement // attaches an NSFetchRequest to this UITableViewController
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Klassement"];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"position" ascending:YES]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.genkDatabase.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
}
Now the ranking is the following. 1,11,12,13,14,2,3,4,5...
I think the problem is that position is a String in my webservice. And my sort descriptor is looking at it as a string. But actually it should look at it as an integer. Does anybody knows how I can do this ?
Thanks in advance.
Even if the "position" is provided as a string from your web service, the best solution would be to store it as number ("Integer 32" or similar) in the Core Data model. The corresponding property of the object will be NSNumber and it will be sorted correctly.
If you really cannot go this way, you could as a workaround try to use localizedStandardCompare as comparison function. I think that sorts strings containing numbers according to their numeric values.
[NSSortDescriptor sortDescriptorWithKey:#"position" ascending:YES
selector:#selector(localizedStandardCompare:)]

Can't parse JSON from data in connectionDidFinishLoading – Maybe it's too much data?

I'm sending out a request to an external API and parsing a response with the SBJson parser. However, I suspect the response is so long, it is somehow getting jumbled.
In my mainviewcontroller.h file I set NSMutableData *receivedData; so that I can use it in the connection methods in the mainviewcontroller.m file.
However, after the connection finishes loading, I execute the following:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *dataString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
NSArray *allData = [dataString JSONValue];
}
However, I get a bunch of errors saying that the JSON is not properly formatted. So, when I look at the JSON, its very long – but here and there, there are problems... for example, the "updated_at" below.
{
"id": 7844333,
"position": 3,
"content": "Cell height is off by 5 pixels",
"created_at": "2012-06-04T20:31:30-05:00",
"updated_at": "2ator": {
"id": 98258,
"name": "Brian"
}
What I think happened above is that updated at has a value of "2012-06...etc" and the next key-value item would be creator : { id, name } but it somehow got jumbled into updated at.
Anyone having a similar problem? I don't think the problem is with the JSONValue because I nslog out the dataString before it gets parsed, and thats where I find the JSON errors.
What I mean by that is that NSString *dataString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding]; is just a long string, but has bad JSON in it because it is jumbled.
Are you using receivedData by more than one connection at once?
:)
I think your json is wrong. For checking that just put json file into the :
http://jsonlint.com/
If it is valid then:
Import the SBJSON framework classes into your project.And try the following code:
SBJSON *parser=[[SBJSON alloc]init];
NSDictionary * dictionary = [parser objectWithString:responseString];
this will give you data into dictionary then by using:
NSString *firstParseData=[dictionary objectForKey:#"your key"];
you can retrieve the data. Hope this will work in your case.

Have TouchJSON return mutable objects?

I am receiving some json from a web service. I parse this using the TouchJSON library.
I keep the data around for the user to change certain values and then I want to return it to the web service.
The JSON object I get contains NSDictionary Objects within the object, like this:
[
{
"id": null,
"created_at": 12332343,
"object": {
"name": "Some name",
"age" : 30
},
"scope": "it stuff",
"kind_id": 1,
"valid": true,
"refering_statement": {
"id": 95
},
"user": {
"id": 1
}
}
]
If I want to change values in this dictionary, I can't because the returned objects from TouchJSON are not mutable.
Is there a way to have have TouchJSON return mutable objects?
or is there a way to have Objective C make an NSDictionary and all its children mutable?
or do I have to just go through every NSDictionary in NSDictionary and copy all data into a mutable copy and then reinsert everything?
Hope someone can help me out on this one:) thanks in advance.
TouchJson has an option to return mutable object rather than normal. (I found it by looking at source code.) Default is to return its "copy", not "mutablecopy".
NSError *error = nil;
jsonString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF32BigEndianStringEncoding];
CJSONDeserializer *jsondeserializer = [CJSONDeserializer deserializer];
jsondeserializer.scanner.options = kJSONScannerOptions_MutableContainers;
NSMutableDictionary *jsonitems = [[NSMutableDictionary alloc] initWithDictionary:[jsondeserializer deserializeAsDictionary:jsonData error:&error]];
You can create a mutable dictionary from a dictionary like this.
(assuming your json parsed dictionary was named jsonDictionary)
NSMutableDictionary *userDictionary = [NSMutableDictionary dictionaryWithDictionary:jsonDictionary];
Hope that solves it for you.