Parse json Data in iOS - ios

I know it's a common question, but I am stuck with is API
How to Parse data from this API : http://dl.bahramradan.com/api/1/get/ig
it contain 20 Object and in every object there are 3 other Objects called "image",date" and "caption"
how can I store all "date" values in an NSMUtableArray in ios?
I did this :
NSString *urlStr = [NSString stringWithFormat:#"http://dl.bahramradan.com/api/1/get/ig"];
NSURL *url = [NSURL URLWithString:urlStr];
NSData *json = [NSData dataWithContentsOfURL:url];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:json options:0 error:NULL];
NSArray *dateArray = [dict objectForKey:#"date"];
But when I run my app, it crashs on the last line, what is wrong ?

I did not check, if your JSON is valid. But there is one obvious mistake in your code: If the JSON consists of 20 objects, I assume those being contained in an array, rather than in a dict!
So first thing to change is
NSArray *array = [NSJSONSerialization JSONObjectWithData:json options:0 error:NULL];
Then, you want to extract the 'date' values for all items and combine these in another array.
Easiest way to achieve that, is by using a KVC Collection Operator
NSArray *dateArray = [array valueForKeyPath:#"#unionOfObjects.date"];
So, what '#unionOfObjects.date' does, is: going through all the objects in the array, look for each of their 'date' value and combine them in the returned array.
Check out this excellent post about KVC Collection Operators!

Related

iOS - Convert a JSON object to an ordered array

I have a JSON file with key/value-pairs for a list of countries and their country-codes. I'm reading it with Objective-C and want to present it in a UIPicker.
Problem is, when I store the JSON data into a NSDictionary, the original order is lost and the order of the UIPicker elements is pretty arbitrary (I know, dictionaries don't have a particular order).
What's the easiest way to preserve to original order? Do I have to create two files, one with the country-codes and one with the country names in the same order and read both into an array? - I really wanna avoid that...
[Edit]
As per request, an excerpt of the JSON-Data (stored in a local file)
{"af":"Afghanistan",
"al":"Albania",
"dz":"Algeria",
"as":"American Samoa",
"ad":"Andorra",
"ao":"Angola",
"ai":"Anguilla",
"aq":"Antarctica",
"ag":"Antigua and Barbuda",
"ar":"Argentina",
"am":"Armenia",
"aw":"Aruba",
"ac":"Ascension Island (Atlantic ocean)",
"au":"Australia",
"at":"Austria",
"az":"Azerbaijan",
"bs":"Bahamas",
"bh":"Bahrain",
"bd":"Bangladesh",
"bb":"Barbados",
"by":"Belarus",
"be":"Belgium",
"bz":"Belize",
"bj":"Benin",
"bm":"Bermuda",
"bt":"Bhutan",
"bo":"Bolivia",
"ba":"Bosnia",
"bw":"Botswana",
"bv":"Bouvet Island (Atlantic ocean)",
"br":"Brazil",
... }
[Edit 2]
I'm using this code to read the JSON data and convert it to a NSDictionary:
NSURL *jsonPath = [[NSBundle mainBundle] URLForResource:#"countries" withExtension:#"json"];
NSString *stringPath = [jsonPath absoluteString];
NSData *countriesJSON = [NSData dataWithContentsOfURL:[NSURL URLWithString:stringPath]];
NSDictionary *parsedJson = [NSJSONSerialization JSONObjectWithData:countriesJSON options:0 error:nil];
You can change your JSON data to
[
{"af":"Afghanistan"},
{"al":"Albania"},
{"dz":"Algeria"},
{"as":"American Samoa"},
{"ad":"Andorra"},
{"ao":"Angola"},
{"ai":"Anguilla"},
...
]
Then use the code like:
NSURL *jsonPath = [[NSBundle mainBundle] URLForResource:#"sample" withExtension:#"json"];
NSData *countriesJSON = [NSData dataWithContentsOfURL:jsonPath];
NSMutableArray *countryArray = [NSJSONSerialization JSONObjectWithData: countriesJSON options:NSJSONReadingMutableContainers error:nil];
The JSON is converted to a ordered array called countryArray. the elements of the countryArray is a NSDictionary instance.
If order is important and you have access to the JSON file, then you could change your JSON to be an array like so:
[
["Afghanistan", "AF"],
["Bangladesh", "BD"]
]
Then when you deserialize it, order will be preserved because the deserialized object will be an array of arrays.
If you don't have access to your JSON file then you could create this array of arrays from your Dictionary in code.
Edit
If you want both quick lookups and an ordering then it's tough to avoid using 2 data structures. With the JSON file you've submitted, it seems you want an array:
NSArray *countriesSorted = [parsedJson.allValues sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
However, it would be better for you to switch the order of values in your json file to be country-name:country-code. Then you could do
NSArray *countryCodesSorted = [parsedJson.allKeys sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSString *firstCountryName = parsedJson[countryCodesSorted[0]];
The issue of order and dictionaries often occurs when the dictionary needs to be displayed in a tableview. The established solution to this is to keep a separate array of dictionary keys alongside the dictionary. You can re-order the array as you (or the user) likes and do a two-stage fetch of dictionary entries via the array. This allows you to keep your original JSON format and internal storage properties/instance variables.
YourClass.m:
#interface MyClass ()
#property NSMutableArray *dictOrder;
#end
#implementation MyClass
- (void)getData
{
self.dict = // Get dictonary from JSON
self.dictOrder = [[self.dict allKeys] mutableCopy];
[self.dictOrder sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
}
// UITableViewDataSource example
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Normal cell re-use stuff
NSString *key = self.dictOrder[indexPath.row];
NSString *country = self.dict[key];
// Populate cell
}
#end

Getting one value from JSON API in Objective-C

I'm trying to get one value from JSON. JSON is located in NSString and it looks like this:
{"coord":{"lon":-122.38,"lat":37.57},"weather":[{"id":300,"main":"Drizzle","description":"Lekka mżawka","icon":"09d"}],"base":"stations","main":{"temp":304.74,"pressure":1017,"humidity":35,"temp_min":300.15,"temp_max":307.59},"visibility":16093,"wind":{"speed":6.7,"deg":250},"clouds":{"all":75},"dt":1437346641,"sys":{"type":1,"id":478,"message":0.0615,"country":"US","sunrise":1437311022,"sunset":1437362859},"id":5357155,"name":"Hillsborough","cod":200}
I'm interested in getting "temp". How should I do that?
Assuming your JSON string was stored as a NSString named JSONString:
NSError *error;
NSDictionary *keys = [NSJSONSerialization JSONObjectWithData:[JSONString dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error:&error];
NSLog(#"temp = %#", keys[#"main"][#"temp"]); // temp = 304.74
To get the main sub item in weather, which is an array with multiple items, you should point out its index to tell the selector which object in the array is the one you are looking for. In this case, it's 0:
NSLog(#"weather = %#", keys[#"weather"][0][#"main"]); // weather = Drizzle

NSMutableData to NSDictionary returning null

I'm writing a program that uses the Instagram API and I'm running into some issues with NSMutableData and NSDictionary.
Since I have to make multiple calls to the API, I decided to create a NSMutableData object, append smaller NSData objects to it and then turn the whole thing into an NSDictionary.
However, after I make a second call to NSMutableData appendData NSData, when I turn NSMutableData into an NSDictionary, the dictionary returns null.
Here's some of my code.
NSMutableData *userData = [[NSMutableData alloc]init]
NSData *feed = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://api.instagram.com/v1/users/17636367/media/recent?access_token=%#",accessToken]]];
[userData appendData:feed];
NSData *moarData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://api.instagram.com/v1/users/17636367/media/recent?access_token=%#&max_id=%#",accessToken, maxID]]];
[userData appendData:moarData];
NSDictionary *dictTwo = [NSJSONSerialization JSONObjectWithData:userData options:NSJSONReadingMutableContainers error:nil];
NSLog(#"%#",dictTwo);
dictTwo returns null. However, when I make only one call to appendData, the dictionary isn't empty.
Thanks.
When you append two separate JSON responses they will not form a JSON.
You can test the final result to see if it is JSON or not with the following link:
JSON validator
You need to parse each query response separately and then apply manipulation on that data: (Ex NSMutableDictionary, NSMutableArray etc).
The first call will return an array or dictionary. Assuming it is a dictionary you would get something like:
{"some":"data"}
This can be parsed correctly. When you make two calls you get:
{"some":"data"}{"other":"data"}
This is not valid JSON. You need to parse each item separately.

Get a single specific value from json

As you might expect, i'm fairly new to obj-C, and i'm constantly trying to build knowledge and experience. But i'm still struggling with a lot of concepts, and that includes JSON data 'catching'.
I've seen many tutorials and guides but i just can't translate them into what i need. Most of the time they layout data in arrays or get multiple values, and (of course) use different variables, which makes everything confusing and unclear to me, even though this should be stupidly simple.
I'm trying to do something very simple :
Get a single value from the open weather API, the temperature.
I'll show you my code which, according to my disgraceful knowledge, should be perfect, but apparently it doesn't work :D
#implementation HomeViewController
{
NSMutableArray *tableData;
NSDictionary *jsonDict;
NSMutableString *title;
}
-(void) viewDidLoad
{
[super viewDidLoad];
NSError *error;
//I create my data array and the string i'll store my value later on
tableData = [[NSMutableArray alloc] init];
title = [[NSMutableString alloc]init];
// Creating the link for the json api so it fits coordinates ; this works but i edited the locations out to clear the code
NSString *s = [[NSString alloc]initWithFormat:#"http://api.openweathermap.org/data/2.5/weather?lat=%.05f&lon=%.05f", _annotation.coordinate.latitude, _annotation.coordinate.longitude];
// I go online and catch the data of the url stored in S
NSData *jSonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:s]];
// This is a dictionary where all my data is stored from jsonData, keys and values all the way
jsonDict = [NSJSONSerialization JSONObjectWithData:jSonData options:NSJSONReadingMutableContainers error:&error];
// I use the string created previously and assign it the value stored in that dictionary, in the TEMP 'folder', right under MAIN.
title = [[jsonDict objectForKey:#"main"]objectForKey:#"main.temp"];
// I assign that title to a label so it appears in my view.
self.tempLabel.text = title;
...
}
There you go. I'm probably missing something very simple but i've been stuck on this and even if i feel I know what i'm doing, i'm probably missing something. So it'd be great if with the answer you give me, you could also tell me what I did wrong :D
Thank you very much for your support and knowledge. This community is amazing :)
Put a breakpoint after assigning value to jsonDict and use
po jsonDict
in the console to print out what you are getting. Then, adjust the code that extracts the value. And use modern Objective-C syntax for it.
Example
title = jsonDict[#"main"][#"temp"];
Note
po is a debugger command that will print out the contents of an object. If you need to print out the contents of a primitive, use p instead.
My guess is
jsonDict = [NSJSONSerialization JSONObjectWithData:jSonData options:NSJSONReadingMutableContainers error:&error];
is trying to create an nsdictionary, but it the results are coming back as an array. Try this:
NSError *e = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: jsonDict options: NSJSONReadingMutableContainers error: &e];
if (!jsonArray) {
NSLog(#"Error parsing JSON: %#", e);
} else {
for(NSDictionary *item in jsonArray) {
NSLog(#"Item: %#", item);
}
}
This should set you right:
title = [[jsonDict objectForKey:#"main"]objectForKey:#"temp"];
To explain the issue, it seems you were referring to temp using a combination of dot syntax in the key.
EDIT: In response to your error:
That error appears when you're trying to find the length of a string on a value that is not of NSString type. Looks like temp is being returned as a number. So, to do what it looks like you're trying to do, you'll wanna convert [[jsonDict objectForKey:#"main"]objectForKey:#"temp"] to an NSString:
NSNumber *temp = [[jsonDict objectForKey:#"main"]objectForKey:#"temp"];
NSString *tempString = [temp stringValue];
OR
NSString *temp = [[[jsonDict objectForKey:#"main"]objectForKey:#"temp"] stringValue];
That will allow you to get the length: temp.length
**EDIT: Unless you're trying to get the length of the array of weather data...in which case i'd like to see more of that code

iOS JSON Parse into NSDictionary and then NSArray with SBJson

It should be so simple but I cannot get it work.
Json response is
([{"id":"1", "x":"1", "y":"2"},{"id":2, "x":"2", "y":"4"}])
NSString *response = [request responseString];
//response is ([{"id":"1", "x":"1", "y":"2"},{"id":2, "x":"2", "y":"4"}])
SBJSON *parser = [[[SBJSON alloc] init] autorelease];
NSDictionary *jsonObject = [parser objectWithString:response error:NULL];
// jsonObject doesn't have any value here..Am I doing something wrong?
NSMutableArray Conversion = [jsonObject valueForKey:NULL];
//Even if I get the value of jsonObject. I don't know what to put for valueForKey here
Conversion shoud have two NSObjects..and each of them should have like
id:1
x:1
y:2
and
id:2
x:2
y:4
Your JSON parser will produce an NSArray from your response string, not an NSDictionary. Note that JSON parsers, including SBJSON, will return either an array object or a dictionary object, depending on the contents of the json that is being parsed.
NSArray *jsonObject = [parser objectWithString:response error:nil];
You can then access the individual items in your array (the array elements will be of type NSDictionary) and use valueForKey: to get the properties of each item.
NSDictionary *firstItem = [jsonObject objectAtIndex:0];
NSString *theID = [firstItem objectForKey:#"id"];

Resources