Multi level JSON reading and writing IOS8 - ios

So the last two days I have been struggling to get data from and to a JSON file, this is because it has multiple levels and the same names. I did not set up this file and can't change the structure so I have to get it working in the way it is. To Pharse JSON form a single level is no problem and it works fine, what I need is to get separate data block from "GOV" and "PRIV" then I need a data block "GENERAL" and "LOCAL" and within those I need to be able to get the "Hospital information as a block but also the separate values. Now I have been trying to get this done for two days and I know im doing something wrong but cant figure it out. I do get data back for example the "GOV" block but then in the output window it is showing a array with access data (<__NSCFArray 0x7fe711f58800>) and the output... I cant break up this output and that is what I need because every value needs to be in a text file in a tableview cell. I know { } denotes NSDictionary [ ] denotes NSArray and I have been reading a lot about JSON and I get the concept but There is little to non for me understandable info when it comes to multi level JSON and equal names (hospital) in this case. I have tried all the available option I could find here on StackOverflow but no succes. So if somebody can push me in the right way I will be gratefull.. part of the code:
NSURL *url = [NSURL URLWithString:getDataURL];
NSData * data = [NSData dataWithContentsOfURL:url];
_jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
_AppListArray = [[NSMutableArray alloc] init];
NSArray *wrapper= [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSDictionary *avatars = [wrapper objectAtIndex:0];
for(NSDictionary *apps in _jsonArray) {
if([[apps objectForKey:#"title"] isEqualToString:#"GOV"]){
NSDictionary*tmp = [apps objectForKey:#"hospital"];
_AppListArray = [tmp objectForKey:#"area"];
}
}
//returns error because _ApplistArray is an array and it can't read the data from the objectkey
for (int i = 0; i < _jsonArray.count; i++)
{
NSString *appName = [[_AppListArray objectAtIndex:i] objectForKey:#"hospitalname"];
NSString *appCondition = [[_AppListArray objectAtIndex:i] objectForKey:#"condition"];
NSString *app avgrating = [[_AppListArray objectAtIndex:i] objectForKey:#"avgrating"];
[_AppListArray addObject:[[Applist alloc]initWithAppName:appName andAppCondition:appCondition andAppURL:appURL]];
}
The _ApplistArray does return the 1ste Hospital data block but as an array and this is were I get stuck.. I need to get another level deeper.....Again the solution probably is easy but JSON is something I never worked with this is my first go. The JSON where I need to get the data from:
[
-{
-hospital: {
-area: [
-{
-hospital: [
-{
hospitalname: "ABC",
avgrating: "2,6",
condition: "UPDATE NEEDED",
},
-{
hospitalname: "DEF",
avgrating: "4,2",
condition: "FINE",
},
],
name: "GENERAL"
}
]
},
title: "GOV"
},
-{
-hospital: {
-area: [
-{
-hospital: [
-{
hospitalname: "GHI",
avgrating: "3",
condition: "INSTALL NEW",
},
-{
hospitalname: "JKL",
avgrating: "0",
condition: "NEW",
},
],
name: "LOCAL"
}
]
},
title: "PRIV"
}
]

Here you go.
NSArray *hospitals = [jsonArray objectForKey:#"mainKey"];// I assumed you getting with some key but change based on your requirement
for (NSDictionary *mainData in hospitals){ // Start of Main Hospital
NSDictionary *hospital = [mainData objectForKey:#"hospital"];
NSArray *areas = [hospital objectForKey:#"area"];
for(NSDictionary *area in areas){// Start of Area
NSArray *innerHospitals = [area objectForKey:#"hospital"];
for(NSDictionary *innerHospital in innerHospitals){
NSString *hospitalName = [innerHospital objectForKey:#"hospitalname"];
NSString *avgrating =[innerHospital objectForKey:#"avgrating"];
NSString *condition =[innerHospital objectForKey:#"condition"];
// Do What Ever you want here
}
NSString *name =[area objectForKey:#"name"];
}// End Of Area
NSString *title =[mainData objectForKey:#"title"];
} // End of Main Hospital
I haven't tested it. But i assume this will work. Have a try and let me know what happens.

The problem is that you need 2 for loops for each "Area".
Area is an Array (1st loop) and each hospital is another Array (2nd loop).
And inside each hospital element is the dictionary with the values you need.
ignoring loops this is how you get the first hospitalname(ABC) assuming _AppListArray has the contents of Area
NSString *appName = _AppListArray[0][#"hospital"][0][#"hospitalname"];
For each 0 you will replace it with the counters for the for loops.

Related

Create dictionary with dictionaries of arrays (sorted by a specific custom object property)?

The title may be confusing, apologies. Maybe someone can advise me on a more appropriate title.
I have a .json file structured as below.
"sections": [{
"title": "Locations",
"key": "location"
}],
"contacts": [{
"title": "Social Worker",
"name": "Mrs X",
"office": "xxxxxxxx",
"location": "Lisburn",
"department": "xxxxxxxx",
"telephone": "xxx xxxxxxxx"
},...
When parsing this, I create an array called contactsArray. I can then create AEContact objects from this array like so:
for (NSDictionary *contactDic in [contactsArray valueForKey:#"contacts"]) {
// Create AEContact objects
_contact = [[AEContact alloc] initWithDictionary:contactDic];
[contacts addObject:_contact];
}
self.contacts = [contacts copy];
In the self.contacts array, the value for the contact.location property is what I am interested in. I need to create separate arrays of related AEContact objects based on the location property, then map these to the location key in my contactArray dictionary
This is what I have tried so far:
NSMutableDictionary *locationsDic = [NSMutableDictionary new];
// Loop through contacts
for (int i = 0; i < self.contacts.count; i++) {
// Sort by location
if ([self.contacts[i] valueForKey:#"location"] == [[[contactsArray valueForKey:#"contacts"] objectAtIndex:i] valueForKey:#"location"]) {
[locationsDic setValue:self.contacts[i] forKey:[[[contactsArray valueForKey:#"contacts"] objectAtIndex:i] valueForKey:#"location"]];
}
}
And the output is:
{
Ballynahinch = "<AEContact: 0x15dda1fc0>";
Bangor = "<AEContact: 0x15dda2210>";
Lisburn = "<AEContact: 0x15dda1c70>";
...
}
When an AEContact object has the same location, it sets it as another key/value in the dictionary and overwrites the previous entry. What I need to happen is something like this:
{
Lisburn = "<AEContact: 0x15dda18f0>",
"<AEContact: 0x15dda18f0>",
"<AEContact: 0x15dda18f0>";
Bangor = "<AEContact: 0x15dda18f0>",
"<AEContact: 0x15dda18f0>",
"<AEContact: 0x15dda18f0>";
}
I'm not sure if the output should should/will look like the preview above, I can only assume as I have not yet achieved my goal. How can I create the related AEContact objects in an array and map them to location key in my locationsDic? Thanks.
The title (and the problem description) are a little tough to follow, but I think you're trying to index an array of (AEContact) objects by their location parameter.
We can clarify this just with some tighter naming and with a find-or-create pattern as we process the input.
NSDictionary *jsonResult = // the dictionary you begin with
NSArray *contactParams = jsonResult[#"contacts"];
NSMutableDictionary *contactsByLocation = [#{} mutableCopy];
for (NSDictionary *contactParam in contactParams) {
NSString *location = contactParam[#"location"];
// here's the important part: find the array of aecontacts in our indexed result, or
// create it if we don't find it
NSMutableArray *aeContacts = contactsByLocation[location];
if (!aeContacts) {
aeContacts = [#[] mutableCopy];
contactsByLocation[location] = aeContacts;
}
AEContact *aeContact = [[AEContact alloc] initWithDictionary:contactParam];
[aeContacts addObject:aeContact];
}
contactsByLocation will be what I think you're looking for.

how to call for json with conditions in ios 9, using objective C

This is my json web response response.
-Itinerary: [
-{
ID: "1",
ValueOne: "2473.05",
ValueTwo: "368.95"
},
-{
ID: "2",
ValueOne: "2453.05",
ValueTwo: "308.95"
}
],
-Details :[
-{
ID:"1",
FirstName:"Graham",
LastName:"Json"
},
-{
ID:"1",
FirstName:"Anuradh",
LastName:"Stackoverflow"
}
]
What should be the response object type.I do like this, is it correct or it does not matter whatever the type
NSDictionary *Results = (NSDictionary *)responseObject;
then I get the response.now what I want is to get itinerary details and
get the Details only where the itinerary ID is equal to Details ID .how can I do that.
NSArray *Itinerary = [Resulsts objectForKey=#"Itinerary"];
NSArray *Itinerary = [Resulsts objectForKey=#"Detailss"];
for(NSDictionary *itinry in Itinerary)
{
NSString *Iid = [itinry objectForKey="ID"];
NSString *ValOne = [itinry objectForKey="ValueOne"];
//like this I'm getting values
//then here I want to get all details which it's `itinerary` `ID` equal to `Details` `ID`.how can I do that.
}
then here I want to get all details which it's itinerary ID equal to Details ID.how can I do that.
Please try this code Hope it will work for you
NSArray *Itinerary = [Resulsts objectForKey=#"Itinerary"];
NSArray *dTinerary = [Resulsts objectForKey=#"Detailss"];
for(int i=0; i<Itinerary;i++)
{
NSString *iID=[[Itinerary objectAtIndex:i] objectForKey:#"ID"];
NSString *dID=[[dTinerary objectAtIndex:i] objectForKey:#"ID"];
if ([iID isEqualToString:dID])
{
// do your thinks here
NSLog(#"%#",[[Itinerary objectAtIndex:i] objectForKey:#"ValueOne"]);
// break;
}
// NSString *Iid = [itinry objectForKey="ID"];
// NSString *ValOne = [itinry objectForKey="ValueOne"];
//like this I'm getting values
//then here I want to get all details which it's `itinerary` `ID` equal to `Details` `ID`.how can I do that.
}

Xcode - Getting object out of an array within an array

I have a JSON array(dictionary?) of objects that are themselves an array. I need to find a value within one of these arrays so that I can compare it later. Part of my JSON data:
[
{
"Name": "Exhibitor",
"Url": "api/congress/exhibitor",
"ResourceType": "Data",
"LastMod": 1389106977
},
{
"Name": "Workshop",
"Url": "api/congress/workshop",
"ResourceType": "Data",
"LastMod": 1389106977
},
{
"Name": "Speaker",
"Url": "api/congress/Speaker",
"ResourceType": "Data",
"LastMod": 1389106977
},
]
My method receives a table name as a parameter and returns a time stamp. How would I receive the time stamp (1389106977) for the table "workshop" for example? This seems so simple but I cannot work it out for 'nested' arrays/dictionaries.
Thanks,
edit:
This is the my code with trojanfoe's added to it.
NSError* localError;
NSMutableArray *syncDataArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (syncDataArray)
{
NSNumber *lastMod = nil;
for (NSDictionary *dict in syncDataArray)
{
NSLog(#"current table is: %#", dict[#"Name"]);
if ([tableName isEqualToString:dict[#"Name"]])
{
lastMod = dict[#"LastMod"];
//break;
}
}
NSLog(#"LastMod = %#", lastMod);
}
else
{
NSLog(#"syncDataArray is empty");
}
This works perfectly and makes sense
The JSON data looks like an array of dictionaries, so you can iterate over the array and test for the "Name" entry:
NSArray *jsonData = ...; // You have converted JSON to Objective-C objects already
NSNumber *lastMod = nul;
for (NSDictionary *dict in jsonData) {
if ([#"Workshop" isEqualToString:dict[#"Name"]]) {
lastMod = dict[#"LastMod"];
break;
}
}
if (lastMod) {
// You found it
}
(Note I am not certain the type of object used to store the "LastMod" object, so you might need to do some debugging to find out).
EDIT If you make extensive use of this data you should immediately convert the JSON data into an array of (custom) model objects, which will make it easier to manipulate the data as your app becomes more complex.
You have an array for dictionaries so it would look something like :
NSNumber *timestamp = [[JSON objectAtIndex:index] objectForKey:#"LastMod"];
NSNumber *timestamp = response[1][#"LastMod"];

how to get JSON object from server as it (in the same order) iPhone

Is there any way to get JSON object from the server in the same order??
For example when i fitch using browser my JSON object return like this:
{
"23": {
"numberOfRecords": "3",
"startDate": "27/11/2013",
"endDate": "31/12/2014",
"question": "How do you rate the new MenaME Portal ?",
"voteScale": "5",
"questions": {
"option1": {
"value": "1",
"option": "Poor",
"voteResult": "50.000"
},
"option2": {
"value": "2",
"option": "Acceptable",
"voteResult": "0.000"
},
"option3": {
"value": "3",
"option": "Good",
"voteResult": "0.000"
},
"option4": {
"value": "4",
"option": "Very Good",
"voteResult": "0.000"
},
"option5": {
"value": "5",
"option": "Excellent",
"voteResult": "50.000"
}
},
"selectedAnswer": "0",
"voteAnswered": "0",
"votes": "6"
}
}
after parsing it with [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error]
the object returned like this :
{
23 = {
endDate = "31/12/2014";
numberOfRecords = 3;
question = "How do you rate the new MenaME Portal ?";
questions = {
option1 = {
option = Poor;
value = 1;
voteResult = "50.000";
};
option2 = {
option = Acceptable;
value = 2;
voteResult = "0.000";
};
option3 = {
option = Good;
value = 3;
voteResult = "0.000";
};
option4 = {
option = "Very Good";
value = 4;
voteResult = "0.000";
};
option5 = {
option = Excellent;
value = 5;
voteResult = "50.000";
};
};
selectedAnswer = 0;
startDate = "27/11/2013";
voteAnswered = 0;
voteScale = 5;
votes = 6;
};
}
Is there any way or framework to get the object as it (in the same order returned from the server) ??
Dictionaries, both in JSON and NSDictionary, are unordered, meaning that it is irrelevant which order you see things in the log. This is defined in the JSON specification and the documentation for NSDictionary.
If it actually matters what order things are displayed in, then either the API you are linking to isn't using correct JSON, or you're doing something wrong in your app. To help with those situations you can use several of the sorted NSDictionary implementations that are around.
Can I ask why you want to ensure the dictionary is maintained in the correct order?
I understand in some cases (mine) an ancient JSON -> XML web service was being called by my app and the client refused to adjust the service so it could accept unordered JSON (valid json) but if you're writing the app, why do you need to ensure that it is in order?
I have a NSMutableDictionary subclass that keeps objects added by setObject:forKey in the order you call the method that can be found here.
It works by storing a NSMutableOrderedSet of keys within the dictionary and then overrides the keyEnumerator method to return an enumerator based on the ordered set
- (NSEnumerator *)keyEnumerator
{
return [self.orderedSetOfKeys objectEnumerator];
}
You could modify the NSMutableDictionary subclass i created to expose the NSMutableOrderedSet in the public header and then modify this set yourself to get an ordered version of your dictionary.. For example:
NSDictionary *JSONWebServiceDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
LNOrderedMutableDictionary *orderedDictionary = [[LNOrderedMutableDictionary alloc] initWithDictionary:JSONWebServiceDictionary];
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:#[#"key1",#"key2",#"key3"]]; //All the keys you are expecting and the order you want them in..
orderedDictionary.orderSet = order; //orderSet does not exist.. it is currently called `array` and not exposed in LNOrderedMutableDictionary.h
I haven't tested the code above but unless you want to create or modify an existing JSON parser then it seems that it is your only option..
If you did want to modify an existing parser then it might just be as simple as replacing dictionary instances with LNOrderedMutableDictionary to keep everything in order.
Another idea to expand the above sample code could be to replace
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:#[#"key1",#"key2",#"key3"]];
with an array returned in the JSONWebServiceDictionary dictionary as arrays keep their order when parsed from JSON so maybe you could do this?
NSMutableOrderedSet *order = [[NSMutableOrderedSet alloc] initWithArray:[JSONWebServiceDictionary objectForKey:#"keyOrderArray"]]];
Look at what you have. If you test the result you got back from JSONObjectWithData (which we'll assume was declared as id jsonObject)
if ([jsonObject isKindOfClass:[NSDictionary class]) { ...
or
NSLog(#"The object type is %#", [jsonObject class]);
you will find that it is indeed an NSDictionary (or perhaps an NSMutableDictionary). That dictionary, as you can see from the dump (or infer from the nearly identical JSON) contains a single entry with a key of "23".
So let's cast the jsonObject to an NSDictionary and reference it:
NSDictionary* jsonDict = (NSDictionary*) jsonObject;
NSDictionary* entry23Dict = [jsonDict objectForKey:#"23"];
Now, if you NSLog entry23Dict you will discover it contains all of the above, absent the { 23 = ... } outermost dictionary.
You can then access, say, "questions" with
NSDictionary* questDict = [entry23Dict objectForKey:#"questions"];
From there the individual "option1", "option2", ... "option5" dictionaries can be accessed in a similar fashion. You simply proceed one layer at a time -- don't get overwhelmed by the entire structure. (It's often helpful, when you're first learning, to NSLog each "layer" as you "peel" it out of the containing structure.)
And, of course, you have all the standard facilities that are available to NSDictionary objects (and NSArray objects, should your JSON contain any [..] arrays). For instance, you can iterate on the keys of the dictionary with
for (NSString* key in jsonDict) {
NSLog(#"This entry's number is %#", key); // For the above will print "23"
NSDictionary* numberedDict = jsonDict[key]; // Using the "new" form of dictionary access
NSString* endDate = numberedDict[#"endDate"]; // Ditto
NSLog(#"The end date is %#", endDate);
}
This is a fairly common problem. It's also probably the most annoying part about iOS. (java doesn't have this issue at all). If you want to get back objects, take a look at restkit.org Specifically this answer may help: https://stackoverflow.com/a/8284343/836450

Google Search with iOS using JSON

Update
It appears resultField is the one that has no value. Will look into this, but I'd still appreciate any advice.
Original Post
I've been set the task of coming up with a basic iOS application that simply makes a search request and then displays the results for university work. I tried to use the Google Custom Search engine but could never get it to work on the iPhone so I've had to resort to the depreciated Google Web Search API (The lecturer is okay with this).
Now, I'm able to make the request, and it returns the JSON data as intended, which I now must parse, I think. Sadly I only have a week to do this, which is crazy as I've never worked with JSON before.
What I'd like is if someone could help me get off the ground with a pointer or two in how to get even just a basic parsing of the JSON data.
I've looked around on Stackoverflow and saw some things that might be helpful like the breakdown structure in the selected answer here.
The person put this together, which when shown in the code makes some sense to me:
A great structure explanation
dictionary (top-level)
sethostname (array of dictionaries)
dictionary (array element)
msgs (string)
status (number)
statusmsg (string)
warns (array)
??? (array element)
Sadly I can't even begin to do the same with the code generated in my app. It takes the form similar to this example code, courtesy of google - I'm no Paris Hilton fan!
Example code from Google.
{"responseData": {
"results": [
{
"GsearchResultClass": "GwebSearch",
"unescapedUrl": "http://en.wikipedia.org/wiki/Paris_Hilton",
"url": "http://en.wikipedia.org/wiki/Paris_Hilton",
"visibleUrl": "en.wikipedia.org",
"cacheUrl": "http://www.google.com/search?q\u003dcache:TwrPfhd22hYJ:en.wikipedia.org",
"title": "\u003cb\u003eParis Hilton\u003c/b\u003e - Wikipedia, the free encyclopedia",
"titleNoFormatting": "Paris Hilton - Wikipedia, the free encyclopedia",
"content": "\[1\] In 2006, she released her debut album..."
},
{
"GsearchResultClass": "GwebSearch",
"unescapedUrl": "http://www.imdb.com/name/nm0385296/",
"url": "http://www.imdb.com/name/nm0385296/",
"visibleUrl": "www.imdb.com",
"cacheUrl": "http://www.google.com/search?q\u003dcache:1i34KkqnsooJ:www.imdb.com",
"title": "\u003cb\u003eParis Hilton\u003c/b\u003e",
"titleNoFormatting": "Paris Hilton",
"content": "Self: Zoolander. Socialite \u003cb\u003eParis Hilton\u003c/b\u003e..."
},
...
],
"cursor": {
"pages": [
{ "start": "0", "label": 1 },
{ "start": "4", "label": 2 },
{ "start": "8", "label": 3 },
{ "start": "12","label": 4 }
],
"estimatedResultCount": "59600000",
"currentPageIndex": 0,
"moreResultsUrl": "http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8..."
}
}
, "responseDetails": null, "responseStatus": 200}
This is the code so far, which as you'll learn quickly does not really do much else than return code similar to the code above.
**My code.**
// query holds the search term
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//append theQuery with search URL
NSString *tempString = [NSString stringWithFormat:#"%#/%#", #"https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=", theQuery];
//Create NSURL out of tempString
NSURL *url = [NSURL URLWithString:tempString];
// Create a request object using the URL.
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Prepare for the response back from the server
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONWritingPrettyPrinted error:&error];
NSDictionary* resultField = [NSDictionary dictionaryWithDictionary:[dictionary objectForKey:#"results"]];
// Send a synchronous request to the server (i.e. sit and wait for the response)
// Check if an error occurred
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
// Do something to handle/advise user.
}
// Convert the response data to a string.
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSArray *results = [dictionary objectForKey:#"results"];
//set label's text value to responseString's value.
endLabel.text = responseString;
Now the main issue I've encountered is that the results array is null all the time. I could really do with a point in the right direction here. Thank you.
It looks like you're having trouble traversing the data structure parsed out of the JSON.
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONWritingPrettyPrinted error:&error];
Assuming the data you passed in is good, this dictionary contains the top-level structure. It has three keys responseData, responseDetails, and responseStatus. (You could see this by NSLogging the dictionary.)
You're then querying that dictionary for the key results. It doesn't exist, so your resultField variable is set to nil. The dictionary's value for the key responseData is another dictionary which does contain a key results -- you need that middle step.
Also, the value for the results key in that second dictionary is an array (of more dictionaries), not a dictionary itself.
There is no need to create a new dictionary each time. For easier reading I'd recommend something like:
[[dictionary objectForKey:#"responseData"] objectForKey:#"results"]
There you have the array of results. You can then add
[ [dictionary objec...] objectAtIndex:0]

Resources