Objective C - Issue when read JSON Key - ios

Hi everyone I am working with a JSON file in my xCode project.
I can easily display the various JSON key but when I call a key it specifies my app crashes and I don't understand why ...
I was very careful to write the keys correctly but it keeps crashing ...
This is my example JSON file
{
"Università" : {
"uniID" : {
"latitudine" : 43.115441,
"longitudine" : 12.389587,
"nome" : "Università per stranieri di Perugia",
"regione" : "Umbria"
},
"uniID" : {
"latitudine" : 41.860348,
"longitudine" : 12.496308,
"nome" : "Università degli Studi Internazionali di Roma ( UNINT )",
"regione" : "Lazio"
},
}
}
When I try to recover the "name" key my app crashes, this is true even if I call "latitude" or "longitude" etc ...
Where am I doing wrong ?
These are the functions I use for reading the JSON file
-(void)setupUniversityLocation:(MKMapView *)mapView {
NSDictionary *dict = [self JSONUniversity];
NSArray *universityArray = [[dict objectForKey:#"Università"] objectForKey:#"uniID"];
for (NSDictionary *uni in universityArray) {
NSString *uniname = [uni objectForKey:#"nome"];
NSLog(#"uniname %#",uniname);
}
}
#pragma mark - Read JSON Data University
-(NSDictionary *)JSONUniversity {
NSString *path = [[NSBundle mainBundle] pathForResource:#"university" ofType:#"json"];
NSData *data = [NSData dataWithContentsOfFile:path];
return [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
}
I also wanted to ask you how can I directly read the keys "name", "latitude" etc ... without where to invoke the "uniID" key? is it possible to bypass a category key?

There is no array in your json file. You should change json file to
{
"Università" : [
{
"latitudine" : 43.115441,
"longitudine" : 12.389587,
"nome" : "Università per stranieri di Perugia",
"regione" : "Umbria"
},
{
"latitudine" : 41.860348,
"longitudine" : 12.496308,
"nome" : "Università degli Studi Internazionali di Roma ( UNINT )",
"regione" : "Lazio"
}
]
}
Use [] to present array instead of {} and below code will work
-(void)setupUniversityLocation:(MKMapView *)mapView {
NSDictionary *dict = [self JSONUniversity];
NSArray *universityArray = [dict objectForKey:#"Università"];
for (NSDictionary *uni in universityArray) {
NSString *uniname = [uni objectForKey:#"nome"];
NSLog(#"uniname %#",uniname);
}
}
#pragma mark - Read JSON Data University
-(NSDictionary *)JSONUniversity {
NSString *path = [[NSBundle mainBundle] pathForResource:#"university" ofType:#"json"];
NSData *data = [NSData dataWithContentsOfFile:path];
return [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
}

There is no Array in the example JSON you posted.
So in this line:
NSArray *universityArray = [[dict objectForKey:#"Università"] objectForKey:#"uniID"];
When you are assuming the output is an array, in actuality it's a dictionary.
If you put a log statement outputting the kind of class returned after that line:
NSLog(#"Kind of class returned from univeristyArray = %#", [universityArray class]);
It will return:
Kind of class returned from univeristyArray = __NSDictionaryI
Right now your structure of the JSON example you posted is:
Top Level Object (Dictionary)
"Università" (Dictionary)
"uniID" (Dictionary)
Another issue with this structure is that you have multiple values for the same key under the "Università" dictionary (i.e. multiple "uniID" which have different associated values)
If you have control over the JSON generated, you have a couple of different options depending on what you're attempting to do:
From your code, it looks like you're attempting to loop through all the "Università" and output their name -- and you're expecting them to be stored in an Array. In this case you'd want to change the "Università" data structure to an Array in the JSON.
Alternatively, make the "nome" value of the university the key for the lower level dictionaries and then fetch them by name (only if the universities names are going to be unique) -- this would be good if you have a large list of universities and you're attempting to only fetch specific ones (by name).
Example of #1:
university.json:
{
"Università" : [
{
"latitudine" : 43.115441,
"longitudine" : 12.389587,
"nome" : "Università per stranieri di Perugia",
"regione" : "Umbria"
},
{
"latitudine" : 41.860348,
"longitudine" : 12.496308,
"nome" : "Università degli Studi Internazionali di Roma ( UNINT )",
"regione" : "Lazio"
},
]
}
setupUniversityLocation:
-(void)setupUniversityLocation {
NSDictionary *dict = [self JSONUniversity];
NSArray *universityArray = [dict objectForKey:#"Università"];
for (NSDictionary *uni in universityArray) {
NSString *uniname = [uni objectForKey:#"nome"];
NSLog(#"uniname %#",uniname);
}
}
Example of #2:
university.json:
{
"Università" : {
"Università per stranieri di Perugia": {
"latitudine" : 43.115441,
"longitudine" : 12.389587,
"regione" : "Umbria"
},
"Università degli Studi Internazionali di Roma ( UNINT )": {
"latitudine" : 41.860348,
"longitudine" : 12.496308,
"regione" : "Lazio"
},
}
}
setupUniversityLocation:
-(void)setupUniversityLocation {
NSDictionary *dict = [self JSONUniversity];
NSDictionary *universityDictionary = [dict objectForKey:#"Università"];
// this is an example of looping through the entire dictionary
// typically you'd use objectForKey when accessing a specific university
for (NSString *universityNameKey in universityDictionary.allKeys) {
NSDictionary *specificUniDictionary = [universityDictionary objectForKey:universityNameKey];
NSLog(#"uniname %#",universityNameKey);
NSLog(#"latitudine %#", [specificUniDictionary objectForKey:#"latitudine"]);
NSLog(#"longitudine %#", [specificUniDictionary objectForKey:#"longitudine"]);
}
}
For most cases I would recommend going with the second option as if it's a large list it's going to be a lot quicker to find a specific item, but it definitely depends on your use case.

Related

TableView from JSON file - sort data

Hi everyone I'm working with a JSON file to populate a UITableView.
The JSON file has two fields that I need to use:
- "First name"
- "region"
The "region" fields must be assigned for the creation of the UITableView sections.
The "name" fields must be sorted according to the section.
JSON File :
{
"Università" : [
{
"nome" : "Università degli Studi di Trento",
"regione" : "Trentino Alto Adige"
},
{
"nome" : "Università per Stranieri di Reggio Calabria \"Dante Alighieri\"",
"regione" : "Calabria"
},
{
"nome" : "Università degli Studi Suor Orsola Benincasa",
"regione" : "Campania"
},
{
"nome" : "Università degli Studi della Calabria ",
"regione" : "Calabria"
},
{
"nome" : "Università degli Studi di Napoli \"L'Orientale\"",
"regione" : "Campania"
}
]
}
As you can see from the JSON file, each "name" has a "region" so they must be sorted that way for example
(section) region 1
(cell) name with region 1
(cell) name with region 1
(cell) name with region 1
(section) region 2
(cell) name with region 2
(cell) name with region 2
(cell) name with region 2
How can I implement this to populate my UITableView?
This is the implementation I have done so far
-(void)retrieveUniversityListFromJSONFile {
/* Interpelliamo il file JSON all'interno del progetto per ottenere i nomi di tutte le università attualmente presenti nel file */
// Nome del file JSON
NSString *JSONFileName = #"university";
NSString *path = [[NSBundle mainBundle] pathForResource:JSONFileName ofType:#"json"];
NSData *data = [NSData dataWithContentsOfFile:path];
// Creazione di un dizionario che eredita informazioni dal file JSON
NSDictionary *JSONDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
// Inizializziamo l'array per prepararla ad accogliere i dati
_universityList = NSMutableArray.new;
for (NSDictionary *dict in JSONDict[#"Università"]) {
// Otteniamo i nomi delle università presenti nel file
NSString *universityName = dict[#"nome"];
// Otteniamo i nomi delle regioni italiane
NSString *regionName = dict[#"regione"];
// Aggiungiamo i risultati per le regioni all'array || _regionList ||
[_regionList addObject:regionName];
// Aggiungiamo i risultati all'array || _universityList||
[_universityList addObject:universityName];
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return _regionList.count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _universityList.count;
}
You need to manipulate the JSON data into an array that can be referenced by the table view's index path. The structure could be an array of dictionaries with each dictionary holding the region, and the list of names associated. You would need to iterate the JSON data and build a new array of dictionaries, adding one for each new region encountered, then adding the name to the array of names in that region's dictionary. Your index path section and row would reference the dictionary and index of the names respectively.
Your function might look like this:
_regionList = [NSMutableArray array];
for (NSDictionary *dict in JSONDict[#"Università"]) {
// Otteniamo i nomi delle università presenti nel file
NSString *universityName = dict[#"nome"];
// Otteniamo i nomi delle regioni italiane
NSString *regionName = dict[#"regione"];
BOOL found = NO;
for (NSDictionary *regDict in _regionList) {
if ([regDict[#"region_name"] isEqualToString:regionName]) {
//Region exists already
found = YES;
if (regDict[#"names"] == nil) {
//name array does not exist, create new array
regDict[#"names"] = [NSMutableArray arrayWithObject:universityName];
} else {
//name array does exist
regDict[#"names"] addObject:universityName];
}
break;
}
if (found == NO) {
//Region does not exist, create new region dictionary
NSMutableDictionary *newRegionDict = [NSMutableDictionary new];
newRegionDict[#"region_name"] = regionName;
newRegionDict[#"names"] = [NSMutableArray arrayWithObject:universityName];
}
}
Example of above data structure:
[
[0]: { "region_name": "Calabria",
"names": [
[0]: "Università per Stranieri di Reggio Calabria \"Dante Alighieri\"",
[1]: "Università degli Studi della Calabria"
]
},
[1]: { "region_name": "Campania",
"names": [
[0]: "Università degli Studi di Napoli \"L'Orientale\"",
[1]: "Università degli Studi Suor Orsola Benincasa"
]
}
]
The number of rows in section would be [_regionList[section][#"names"] count];
Your -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section might look like this:
...
NSDictionary *region = _regionList[section];
NSString *regionName = _regionList[#"region_name"];
return regionName;
Your -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath:
...
NSDictionary *region = _regionList[indexPath.section];
NSString *uniName = _regionList[#"names"][indexPath.row];
...
Don't forget to call [yourTableView reloadData] after manipulating data referenced by the table.

Mapping array to dictionary using object in array as key

I'm using RestKit in my iOS app and I can't seem to get this to work. I have the following JSON array:
{
"id" : 1,
"streamable" : true
},
{
"id" : 2,
"streamable" : true
},
{
"id" : 3,
"streamable" : true
}
I would like to end up with a dictionary looking like this:
{
"1" : {
"id" : 1,
"streamable" : true
},
"2" : {
"id" : 2,
"streamable" : true
}
}
Where I use the id value as the dictionary's key. How would I map this using RestKit?
Assume, you have array of Disctionaries , iterate through the dictionaries and find for the id make this a new Dictionary
For Instance :
NSArray *arrDictionaries = // .....
NSDictionary *result =[[NSDictionary alloc]init];
for(NSDictionary *dict in arrDictionaries){
NSstring *key = [dict objectForKey:#"id"];
[result setObject:dict forKey:key];
}
Note : I've not tested

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 parse JSON multi-array

I need to parse the JSON file provided by Google Maps API
Then i use the AFNetworkingRequestHow to get the JSON response.
I built this dictionary:
NSDictionary *jsonDict = (NSDictionary *) JSON;
NSArray *rows = [jsonDict objectForKey:#"rows"];
But now, how can i reach the first value field of duration tag?
JSON File to parse:
{
"destination_addresses" : [ "San Francisco, CA, USA", "Victoria, BC, Canada" ],
"origin_addresses" : [ "Vancouver, BC, Canada", "Seattle, WA, USA" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "1,527 km",
"value" : 1527251
},
"duration" : {
"text" : "15 hours 0 mins",
"value" : 54010
},
"status" : "OK"
},
{
"distance" : {
"text" : "112 km",
"value" : 111906
},
"duration" : {
"text" : "3 hours 1 min",
"value" : 10885
},
"status" : "OK"
}
]
}
}
Try
NSDictionary *jsonDict = (NSDictionary *) JSON;;
NSArray *rows = jsonDict[#"rows"];
NSDictionary *row = rows[0];
NSArray *elements = row[#"elements"];
NSDictionary *element = elements[0];
NSDictionary *duration = element[#"duration"];
NSInteger value = [duration[#"value"] integerValue];
[json objectForKey:#"elements"]
is an NSArray. You can't initialize an NSDictionary directly with an array.
(in JSON, { and } denote key-value pairs, like NSDictionary, whereas [ and ] delimit ordered lists like NSArray, that's why the mapping is done as it is...)
Following thinks can you understanding for development time so it may help lot.
You can use the following code:
NSString *valueString = [[[[[rows objectAtindex:0]objectForKey:#"elements" ]objectAtindex:0]objectForKey:#"duration"] objectForKey:#"value"];
//if you want integer value
NSInteger value = [valueString integerValue];

ios json parsing sub collection

I have a json collection I am able to parse perfectly fine 1 level deep, but each item in the main collection has a collection in it. I am not quite sure how to access 'item' to get the sub collection like I did with the main collection...
NSString *response = [request responseString];
NSDictionary *json = [response JSONValue];
NSArray *items = [json valueForKeyPath:#"item"];
for (id item in items)
{
mainObject.name = [item objectForKey:#"name"]; //this works fine
// How do I get sub collection from item?
}
Some of the json:
{"item":
{
"available_at" : null,
"created_at" : "2011-12-09T19:52:23Z",
"lo_id" : 30,
"id" : 24,
"merchant_id" : 1,
"order_id" : 25,
"reach_local_link" : null,
"status" : null,
"token" : "12-258847891-1",
"updated_at" : "2011-12-09T19:52:23Z",
"url" : "api/dir/v1/item/12-258847891-1/print",
"subitem1" :
{
"area" : "local",
"broker_id" : "",
"broker_id" : null,
"category" :
{
"category":....
In the example, there could be multiple sub items like subitem1. I need to get the collection of those and have another for loop inside the current one.
item will simply be a dictionary or array if it is one in the JSON object. For example, you should be able to do this:
NSDictionary *subitem1 = [item objectForKey:#"subitem1"];
It's simply a NSDictionary in there, so you can use it as one.
I really recommend logging the Objective-C representation of your JSON object, it makes it easier to work with it:
NSLog(#"%#", json);
Warning
It's strongly recommended to check the type of the objects you load before assuming that they really are dictionaries, strings or arrays. If they aren't, you'll notice that your application is going to crash.

Resources