Retrieve nested objects from JSON - Objective C - objective-c

I seem to be having a small issue with the parsing through a nested JSON result. The following code works perfectly if the JSON is not nested. I'm a littler perplexed on how to proceed as every attempted (through examples of others) have failed.
So, to test this I'm using the following API from https://developer.worldweatheronline.com/page/explorer-free
I simply would like to get my current temperature (temp_c).
Below is the code calling the service. Note that I have an NSObject that will fill the data, but of course I can't seem to get to that stage. Also it is an NSMutableArray throughout. Again, I don't think that is the issue but provides context.
-(void)retrieveLocalWeatherService {
NSURL *url = [NSURL URLWithString:getLocalWeather];
NSData *data = [NSData dataWithContentsOfURL:url];
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//set up array and json call
weatherArray = [[NSMutableArray alloc]init];
//Loop through the JSON array
for (int i = 0; i< jsonArray.count; i++)
{
//create our object
NSString *nTemp = [[jsonArray objectAtIndex:i]objectForKey:#"temp_C"];
NSString *nPressure = [[jsonArray objectAtIndex:i]objectForKey:#"pressure"];
NSString *nHumidity = [[jsonArray objectAtIndex:i]objectForKey:#"humidity"];
//Add the object to our animal array
[weatherArray addObject:[[LocalWeather alloc]initWithtemp:(nTemp) andpressure:nPressure andhumidity:nHumidity]];
}
Here is the JSON response.
{
"data": {
"current_condition": [
{
"cloudcover": "75",
"FeelsLikeC": "31",
"FeelsLikeF": "88",
"humidity": "70",
"observation_time": "05:15 AM",
"precipMM": "0.0",
"pressure": "1011",
"temp_C": "28",
"temp_F": "82",
"visibility": "10",
"weatherCode": "116",
"weatherDesc": [
{
"value": "Partly Cloudy"
}
],
"weatherIconUrl": [
{
"value": "http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0002_sunny_intervals.png"
}
],
"winddir16Point": "N",
"winddirDegree": "10",
"windspeedKmph": "41",
"windspeedMiles": "26"
}
],
"request": [
{
"query": "Brisbane, Australia",
"type": "City"
}
],
I cut off the JSON service as it goes for miles, so where am I going wrong? I believe its somewhere within "for-loop" but am unsure where. I know its major node is "data" and then sub-node is "current_condition". Should I be digging through the JSON results? If what is the best approach.
BTW, I'm getting a response from the server with the entire JSON result..clearly a parsing issue on my part.
Thanks in advance!
please be kind i'm a newbie.

You are parsing your JSON data in wrong way, you are parsing JSON directly to Array but as per your JSON format your JSON will return an NSDictionary not NSArray.
-(void)retrieveLocalWeatherService {
NSURL *url = [NSURL URLWithString:getLocalWeather];
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *weatherJson = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSArray *currentConditionArray = [weatherJson valueForKeyPath:#"Data.current_condition"];
//set up array and json call
weatherArray = [[NSMutableArray alloc]init];
//Loop through the JSON array
for (NSDictionary *item in currentConditionArray)
{
//create our object
NSString *nTemp = [item objectForKey:#"temp_C"];
NSString *nPressure = [item objectForKey:#"pressure"];
NSString *nHumidity = [item objectForKey:#"humidity"];
//Add the object to our animal array
[weatherArray addObject:[[LocalWeather alloc]initWithtemp:(nTemp) andpressure:nPressure andhumidity:nHumidity]];
}
}

Related

How to iterate through a simple JSON object in Objective-C?

I'm very new to Objective-C, I'm a hardcore Java and Python veteran.
I've created an Objective-C script that calls a URL and gets the JSON object returned by the URL:
// Prepare the link that is going to be used on the GET request
NSURL * url = [[NSURL alloc] initWithString:#"http://domfa.de/google_nice/-122x1561692/37x4451198/"];
// Prepare the request object
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
// Prepare the variables for the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
// Construct a Array around the Data from the response
NSArray* object = [NSJSONSerialization
JSONObjectWithData:urlData
options:0
error:&error];
//NSLog(object);
// Iterate through the object and print desired results
I've gotten this far:
NSString* myString = [#([object count]) stringValue];
NSLog(myString);
Which returns the size of this array, but how can I loop through this JSON object and print each element?
Here's the JSON I'm loading:
{
"country": "United States",
"sublocality_level_1": "",
"neighborhood": "University South",
"administrative_area_level_2": "Santa Clara County",
"administrative_area_level_1": "California",
"locality": "City of Palo Alto",
"administrative_area_level_3": "",
"sublocality_level_2": "",
"sublocality_level_3": "",
"sublocality":""
}
The top-level object your JSON object is a dictionary, not an array, as indicated by the curly braces. If you are not sure whether you are going to get an array or a dictionary back, you can do some safety checking like this:
// Construct a collection object around the Data from the response
id collection = [NSJSONSerialization JSONObjectWithData:urlData
options:0
error:&error];
if ( collection ) {
if ( [collection isKindOfClass:[NSDictionary class]] ) {
// do dictionary things
for ( NSString *key in [collection allKeys] ) {
NSLog(#"%#: %#", key, collection[key]);
}
}
else if ( [collection isKindOfClass:[NSArray class]] ) {
// do array things
for ( id object in collection ) {
NSLog(#"%#", object);
}
}
}
else {
NSLog(#"Error serializing JSON: %#", error);
}
Well for starters, the JSON you linked to is not an array, it is a dictionary.
NSDictionary* object = [NSJSONSerialization
JSONObjectWithData:urlData
options:0
error:&error];
There are a number of ways to iterate through all of the keys/values, and here is one:
for(NSString *key in [object allKeys])
{
NSString *value = object[key]; // assuming the value is indeed a string
}

AFNetworking and compex JSON structures

I'm writing a native application for iPhone, I'm quite new to the subject.
Using AFNetworking I request (with POST) and process the JSON reply.
But I've noticed that once the JSON response is more complex:
{
"isFound": "YES",
"timestamp": "2013-06-12 22:46:47",
"screenTitle": "Perla Review",
"placeName": "Perla",
"placeUniqueId": "101",
"placeCategory": "PUB",
"username": "#jim",
"userImgURL": "",
"gender": "male",
"infoMsg": "TBD",
"youLike": "Like",
"likesInfoMsg": "",
"revInfoList": [
{
"type": 0,
"data": "",
"text": ""
},
{
"type": 1,
"data": "2",
"text": ""
},
{
"type": 2,
"data": "3",
"text": ""
}
],
"commentsList": []
}
Then AFNetworking fails to read and construct the sub arrays (revInfoList & commentsList).
Am I doing something wrong, or AFNetworking does not support such json structures?
Here is my objective C code to request the data and process the reply:
static NSString *const myAPIBaseURL = #"http://somedomain.com/api/";
NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:myAPIBaseURL]];
NSString *reqPath = #"review/review_fullinfo";
// prepare params
NSString *reqData_loginUsername = [[[Storage_Modal alloc] init] getLoginUsername];
NSString *reqData_currentCoordinatesLat = [[NSNumber numberWithDouble:[appDelegateInst.myCurrentLocation coordinate].latitude] stringValue];
NSString *reqData_currentCoordinatesLon = [[NSNumber numberWithDouble:[appDelegateInst.myCurrentLocation coordinate].longitude] stringValue];
NSString *reqData_reviewUniqueId = reviewUniqueId;
NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:
#"json", #"format",
reqData_loginUsername, #"loginUsername",
reqData_currentCoordinatesLat, #"currentCoordinatesLatitude",
reqData_currentCoordinatesLon, #"currentCoordinatesLongitude",
reqData_reviewUniqueId, #"reviewUniqueId",
nil];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
[client setDefaultHeader:#"Accept" value:#"application/json"];
[client postPath:reqPath parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *xxx = responseObject;
// 'xxx' contains all the top level keys and values, but the sub arrays are empty... why?
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"SERVER ERROR: %#", error);
}
**NOTE: Please forgive me if there is a syntax error in the objective-C code, I had to collect the code from multiple functions.
Thank you.
AFNetworking uses NSJSONSerialization to convert your JSON into a Foundation object, usually an NSDictionary or NSArray. NSJSONSerialization conforms strictly to RFC 4627.
The JSON response you've posted is valid JSON, so there are only 3 causes I can think of for the behavior you describe:
Your server is returning a different payload than the one you posted here
Your server is encoding the payload incorrectly
You're incorrect about what the xxx NSDictionary contains
You can test #1 by looking at your AFJSONRequestOperation's responseString and responseData properties. #2 and #3 can both be tested by inspecting the xxx object carefully. If you post the output of these objects here, we can help you diagnose better.
Your AFNetworking code and your expected JSON both look fine, so I don't think it's an issue with AFNetworking.

Can I write JSON data to a file in iOS/Objective-C?

I need to write JSON data to a file using Objective-C. My data looks something like this:
data = {
"NrObjects" : "7",
"NrScenes" : "5",
"Scenes" : [
{ "dataType" : "label", "position" : [20, 20, 300, 300], "value" : "Hello" },
{ "dataType" : "label", "position" : [20, 60, 300, 300], "value" : "Hi There" }
]
}
It may get more complex than this, but what I need to know is whether I can do this with Obj-C, i.e., create an object of this form, write the data to a file, and read it back.
There is a class specifically made for this, its called NSJSONSerialization.
You read it like this:
NSArray* jsonResponse = [NSJSONSerialization JSONObjectWithData:theResponse
options:kNilOptions
error:&error];
and write it like this:
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:userDetails
options:kNilOptions
error:&error];
write:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonObject];
[data writeToFile:path atomically:YES];
read:
NSData *data = [NSData dataWithContentsOfFile:path];
NSDictionary *jsonObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Best approaches on "filling" a json file , iOS?

I am working on an application and i need to send some data to my server. The data is in json format and more specific the json file looks like this :
{
"eventData": {
"eventDate": "Jun 13, 2012 12:00:00 AM",
"eventLocation": {
"latitude": 43.93838383,
"longitude": -3.46
},
"text": "hjhj",
"imageData": "raw data",
"imageFormat": "JPEG",
"expirationTime": 1339538400000
},
"type": "ELDIARIOMONTANES",
"title": "accIDENTE"
}
So i have tried to hardcode the data in my json file and everything works ok. Now what i am trying to do is to fill my json file , using variables so everything can work automatcally when data changes. What would a good approach be for that?? Some sample code would be highly appreciated as i am very new to obj-c. Thanks for ur time! :D
EDIT
Ok so an NSDictionary seems a nice way to go.
But how can i create a dictionary to look like the json format?? I ve only used dictionaries like this :
NSArray *keys = [NSArray arrayWithObjects:#"eventDate", #"eventLocation", #"latitude" nil];
NSArray *objects = [NSArray arrayWithObjects:#"object1", #"object2", #"object3", nil];
dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
For the langitude and longitude for example it is a pair of key and value but for the rest??
All you need is a NSDictionary containing your keys and values. Since iOS5, you can proceed with the following code
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:myDictionary
options:NSJSONWritingPrettyPrinted
error:&error];
if (!jsonData) {
NSLog(#"Got an error: %#", error);
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// ...
}
I have used this library . It is very simple and useful. And for tutorial check this site.

How do I parse JSON with Objective-C?

I am new to iPhone. Can anyone tell me the steps to follow to parse this data and get the activity details, first name, and last name?
{
"#error": false,
"#data": {
"": {
"activity_id": "35336",
"user_id": "1",
"user_first_name": "Chandra Bhusan",
"user_last_name": "Pandey",
"time": "1300870420",
"activity_details": "Good\n",
"activity_type": "status_update",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-1627435117.jpg"
},
"boolean": "1",
"1": {
"1": {
"photo_1_id": "9755"
},
"activity_id": "35294",
"album_name": "Kalai_new_Gallery",
"user_id": "31",
"album_id": "9754",
"user_first_name": "Kalaiyarasan",
"user_last_name": "Balu",
"0": {
"photo_0_id": "9756"
},
"time": "1300365758",
"activity_type": "photo_upload",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/"
},
"3": {
"activity_id": "35289",
"user_id": "33",
"user_first_name": "Girija",
"user_last_name": "S",
"time": "1300279636",
"activity_details": "girija Again\n",
"activity_type": "status_update",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-33-6361851323080768.jpg"
},
"2": {
"owner_first_name": "Girija",
"activity_id": "35290",
"activity_details": "a:2:{s:4:\"html\";s:51:\"!user_fullname and !friend_fullname are now friends\";s:4:\"type\";s:10:\"friend_add\";}",
"activity_type": "friend accept",
"owner_last_name": "S",
"time": "1300280400",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-33-6361851323080768.jpg",
"owner_id": "33"
},
"4": {
"activity_id": "35288",
"user_id": "33",
"user_first_name": "Girija",
"user_last_name": "S",
"time": "1300279530",
"activity_details": "girija from mobile\n",
"activity_type": "status_update",
"photo_url": "http://184.73.155.44/hcl-meme/QA_TEST/sites/default/files/pictures/picture-33-6361851323080768.jpg"
}
}
}
With the perspective of the OS X v10.7 and iOS 5 launches, probably the first thing to recommend now is NSJSONSerialization, Apple's supplied JSON parser. Use third-party options only as a fallback if you find that class unavailable at runtime.
So, for example:
NSData *returnedData = ...JSON data, probably from a web request...
// probably check here that returnedData isn't nil; attempting
// NSJSONSerialization with nil data raises an exception, and who
// knows how your third-party library intends to react?
if(NSClassFromString(#"NSJSONSerialization"))
{
NSError *error = nil;
id object = [NSJSONSerialization
JSONObjectWithData:returnedData
options:0
error:&error];
if(error) { /* JSON was malformed, act appropriately here */ }
// the originating poster wants to deal with dictionaries;
// assuming you do too then something like this is the first
// validation step:
if([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *results = object;
/* proceed with results as you like; the assignment to
an explicit NSDictionary * is artificial step to get
compile-time checking from here on down (and better autocompletion
when editing). You could have just made object an NSDictionary *
in the first place but stylistically you might prefer to keep
the question of type open until it's confirmed */
}
else
{
/* there's no guarantee that the outermost object in a JSON
packet will be a dictionary; if we get here then it wasn't,
so 'object' shouldn't be treated as an NSDictionary; probably
you need to report a suitable error condition */
}
}
else
{
// the user is using iOS 4; we'll need to use a third-party solution.
// If you don't intend to support iOS 4 then get rid of this entire
// conditional and just jump straight to
// NSError *error = nil;
// [NSJSONSerialization JSONObjectWithData:...
}
Don't reinvent the wheel. Use json-framework or something similar.
If you do decide to use json-framework, here's how you would parse a JSON string into an NSDictionary:
SBJsonParser* parser = [[[SBJsonParser alloc] init] autorelease];
// assuming jsonString is your JSON string...
NSDictionary* myDict = [parser objectWithString:jsonString];
// now you can grab data out of the dictionary using objectForKey or another dictionary method
NSString* path = [[NSBundle mainBundle] pathForResource:#"index" ofType:#"json"];
//将文件内容读取到字符串中,注意编码NSUTF8StringEncoding 防止乱码,
NSString* jsonString = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//将字符串写到缓冲区。
NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
id allKeys = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONWritingPrettyPrinted error:&jsonError];
for (int i=0; i<[allKeys count]; i++) {
NSDictionary *arrayResult = [allKeys objectAtIndex:i];
NSLog(#"name=%#",[arrayResult objectForKey:#"storyboardName"]);
}
file:
[
{
"ID":1,
"idSort" : 0,
"deleted":0,
"storyboardName" : "MLMember",
"dispalyTitle" : "76.360779",
"rightLevel" : "10.010490",
"showTabBar" : 1,
"openWeb" : 0,
"webUrl":""
},
{
"ID":1,
"idSort" : 0,
"deleted":0,
"storyboardName" : "0.00",
"dispalyTitle" : "76.360779",
"rightLevel" : "10.010490",
"showTabBar" : 1,
"openWeb" : 0,
"webUrl":""
}
]
JSON parsing using NSJSONSerialization
NSString* path = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"json"];
//Here you can take JSON string from your URL ,I am using json file
NSString* jsonString = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSArray *jsonDataArray = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&jsonError];
NSLog(#"jsonDataArray: %#",jsonDataArray);
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];
if(jsonObject !=nil){
// NSString *errorCode=[NSMutableString stringWithFormat:#"%#",[jsonObject objectForKey:#"response"]];
if(![[jsonObject objectForKey:#"#data"] isEqual:#""]){
NSMutableArray *array=[jsonObject objectForKey:#"#data"];
// NSLog(#"array: %#",array);
NSLog(#"array: %d",array.count);
int k = 0;
for(int z = 0; z<array.count;z++){
NSString *strfd = [NSString stringWithFormat:#"%d",k];
NSDictionary *dicr = jsonObject[#"#data"][strfd];
k=k+1;
// NSLog(#"dicr: %#",dicr);
NSLog(#"Firstname - Lastname : %# - %#",
[NSMutableString stringWithFormat:#"%#",[dicr objectForKey:#"user_first_name"]],
[NSMutableString stringWithFormat:#"%#",[dicr objectForKey:#"user_last_name"]]);
}
}
}
You can see the Console output as below :
Firstname - Lastname : Chandra Bhusan - Pandey
Firstname - Lastname : Kalaiyarasan - Balu
Firstname - Lastname : (null) - (null)
Firstname - Lastname : Girija - S
Firstname - Lastname : Girija - S
Firstname - Lastname : (null) - (null)
I recommend and use TouchJSON for parsing JSON.
To answer your comment to Alex. Here's quick code that should allow you to get the fields like activity_details, last_name, etc. from the json dictionary that is returned:
NSDictionary *userinfo=[jsondic valueforKey:#"#data"];
NSDictionary *user;
NSInteger i = 0;
NSString *skey;
if(userinfo != nil){
for( i = 0; i < [userinfo count]; i++ ) {
if(i)
skey = [NSString stringWithFormat:#"%d",i];
else
skey = #"";
user = [userinfo objectForKey:skey];
NSLog(#"activity_details:%#",[user objectForKey:#"activity_details"]);
NSLog(#"last_name:%#",[user objectForKey:#"last_name"]);
NSLog(#"first_name:%#",[user objectForKey:#"first_name"]);
NSLog(#"photo_url:%#",[user objectForKey:#"photo_url"]);
}
}