Parse two JSON objects - ios

When i send API i'm getting JSON response like this.
{"ABC":[{"ID1":"response","ID2":"response","ID3":"response","ID4":"response","ID5":"response"},{"ID1":"response","ID2":"response","ID3":"response","ID4":"response","ID5":"response"},{"ID1":"response","ID2":"response","ID3":"response","ID4":"response","ID5":"response"}],"status":"OK","count":3}
{"XYZ":[{"id1":"response"},{"id1":"response"},{"id1":"response"}],"status":"OK","count":3}
Here i'm getting two JSON objects in the response. How to store this data in MutableArrays.
My code is...
//Getting data from server through JSON approach ...
self.urlSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
self.urlReq= [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[[NSString alloc] initWithFormat:#"http://MyApiName"]]];
self.dataTask = [self.urlSession dataTaskWithRequest:self.urlReq completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!(data == nil)) {
self.loginDic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"data : %#", data);
NSLog(#"Login Dic : %#", [self.loginDic objectForKey:#"ABC"]);
if (!(self.loginDic == nil)) {
self.integer = [[self.loginDic objectForKey:#"ABC"] count];
if ([[self.loginDic objectForKey:#"status"] isEqualToString:#"OK"] && (!(self.integer == 0))) {
self.ID1 = [[NSMutableArray alloc]init];
self.ID2 = [[NSMutableArray alloc]init];
self.ID3 = [[NSMutableArray alloc]init];
self.ID4 = [[NSMutableArray alloc]init];
self.ID5 = [[NSMutableArray alloc]init];
for (int i=0; i<self.integer; i++) {
[self.ID1 addObject:[[[self.loginDic objectForKey:#"ABC"] objectAtIndex:i] objectForKey:#"ID1"]];
[self.ID2 addObject:[[[self.loginDic objectForKey:#"ABC"] objectAtIndex:i] objectForKey:#"ID2"]];
[self.ID3 addObject:[[[self.loginDic objectForKey:#"ABC"] objectAtIndex:i] objectForKey:#"ID3"]];
[self.ID4 addObject:[[[self.loginDic objectForKey:#"ABC"] objectAtIndex:i] objectForKey:#"ID4"]];
[self.ID5 addObject:[[[self.loginDic objectForKey:#"ABC"] objectAtIndex:i] objectForKey:#"ID5"]];
}
NSLog(#"%#", self.ID1);
NSLog(#"%#", self.ID2);
} else {
}
} else {
}
} else {
}
}];
[self.dataTask resume];
}
I'm getting data, but I'm getting loginDic = null.

after you get AB , its array of Dictionary
you can easily use this valueForKeyPath like:
NSArray * AB = #[#{
#"ID1":#"response",
#"ID2":#"response",
#"ID3":#"response",
#"ID4":#"response",
#"ID5":#"response",
},#{
#"ID1":#"response",
#"ID2":#"response",
#"ID3":#"response",
#"ID4":#"response",
#"ID5":#"response"
}];
NSArray * ID1 = [AB valueForKeyPath:#"ID1"];
NSArray * ID2 = [AB valueForKeyPath:#"ID2"];

How to receive two JSON objects at a time?
The JSON you show is indeed two valid JSON encodings concatenated. If your server is doing this and there is nothing you can do to fix that then you can try to fix it yourself:
Any occurrence of ][, }{, ]{ or }[ with any amount of white space between the two characters is the end of one JSON encoding and the start of the next. Construct an NSRegularExpression to find these sequences and replace them with the same close/open bracket/brace combination but with a comma (,) in between them.
Add a single [ at the start and a single ] at the end.
These two steps will converted your concatenated JSON encodings into a JSON array of the individual encodings. Now parse and process as usual remembering you first need to index into the outermost array to access the particular JSON response before your index into the response to access the elements you need.
HTH

Related

Corruption of NSString or encoding issue in Objective C

Please see code below:
+ (void)splashDataFromJSON:(NSData *)objectNotation error:(NSError **)error
{
NSError *localError = nil;
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:objectNotation options:0 error:&localError];
if (localError != nil) {
*error = localError;
}
NSMutableArray* btms = [[NSMutableArray alloc] init];
NSMutableDictionary* btmManufacturerResolutionDictionary = [[BTMCache sharedManager] btmManufacturerResolutionDictionary];
NSArray *results = [parsedObject valueForKey:#"results"];
NSLog(#"Count %d", parsedObject.count);
NSString* imageBaseUrl = [[parsedObject valueForKey:#"general"] valueForKey:#"image_base_url"];
imageBaseUrl = [imageBaseUrl stringByAppendingString:#"hdpi/"];
NSString* splashImageName = [[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"img"];
NSString* splashAdvertiserURL = [[[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"url"] copy];
NSMutableString* appendedString = [[NSMutableString alloc] init];
for(int i =0 ;i<[splashAdvertiserURL length]; i++) {
char character = [splashAdvertiserURL characterAtIndex:i];
printf(&character);
sleep(0.1);
if (character != "!")
{
[appendedString appendFormat:#"%c", character];
}
}
[[SplashData sharedManager] setSplashAdvertiserURL:appendedString];
[[SplashData sharedManager] setSplashImageName:splashImageName];
splashAdvertiserURL = [[SplashData sharedManager] splashAdvertiserURL];
}
The point of interest is in splashAdvertiserURL. When I receive this data and print it out using po, it comes out as "https://radar.com/ref/go/84/". This is fine and what was expected. When I look at the incoming data in JSONLint it looks like this:
"general": {
"image_base_url": "https:\/\/radar.com\/img\/manufacturers\/",
"splash": {
"img": "image1.png",
"url": "https:\/\/radar.com\/ref\/go\/84\/"
}
},
As you can see, further on I put the NSString into a singleton with an NSString property. Nothing abnormal here. I then proceed to retrieve it to see that all is ok. Further to this the program continues. In another class I wish to retrieve this information, and when I try and do that, it throws EXC_BAD_ACCESS. There appears to be garbage in there.
I then put in a loop in the code as you can see to print out the characters one at a time. Very curiously, when I print that out using po I get:
https://
r
a
d
ar.com/ref/go/8 4!/"
Exactly in that format. If I then proceed to hardcode the string https://radar.com/ref/go/84/ - including escape characters and everything, then all works fine. No issues. If I handle a normal string incoming without escape characters it stores fine in the singleton as well, no issue. enter code here
I am pretty stumped here as to what is going on. Can someone assist?
Thank you
For URL you received as string you need to encode before use it to in your app. Have a look at below code:
NSString *sampleUrl = #"https:\/\/radar.com\/ref\/go\/84\/";
NSString *encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];

How to create Array of Dictionaries from comma separated strings?

I am receiving comma separated string as below which is to be converted to array of dictionaries.I tried using [myString componentsSeparatedByString:#","]; which however gives a totally different output.What is the correct way of converting it?
NSString *cancellationStr ==> [{"cutoffTime":"0-2","refundInPercentage":"0"},{"cutoffTime":"2-3","refundInPercentage":"50"},{"cutoffTime":"3-24","refundInPercentage":"90"}]
NSArray *array = [cancellationStr componentsSeparatedByString:#","];
//Gives response like below
(
"[{\"cutoffTime\":\"0-2\"",
"\"refundInPercentage\":\"0\"}",
"{\"cutoffTime\":\"2-3\"",
"\"refundInPercentage\":\"50\"}",
"{\"cutoffTime\":\"3-24\"",
"\"refundInPercentage\":\"90\"}]"
)
The code to fetch and parse using a singleton HTTP class
NSString *urlString=[NSString stringWithFormat:#"%#%#sourceCity=%#&destinationCity=%#&doj=%#",BASE_URL,AVAILABLE_BUSES,source,destination,dateStr];
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url= [NSURL URLWithString:urlString];
SuccessBlock successBlock = ^(NSData *responseData){
NSError *error;
jsonDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
bArray = [jsonDictionary objectForKey:#"apiAvailableBuses"];
};
FailureBlock failureBlock = ^(NSError *error){
NSLog(#"%#",error);
};
HTTPRequest *request = [[HTTPRequest alloc]initWithURL:url successBlock:successBlock failureBlock:failureBlock];
[request startRequest];
The above success block receives the string which then I am looking to convert.
NSString *cancellationStr = [[bArray objectAtIndex:rowIndex]valueForKey:#"cancellationPolicy"];
bObject.cancellationPolicy = [cancellationStr componentsSeparatedByString:#","];
NSLog(#"Cancellation Array : %#",bObject.cancellationPolicy);
So, "apiAvailableBusses" is an array of elements like this one:
{
"operatorId":196,
"operatorName":"Sahara Bus",
"departureTime":"6:45 PM",
"mTicketAllowed":false,
"idProofRequired":false,
"serviceId":"1602",
"fare":"450",
"busType":"Sahara Hitech Non A/c",
"routeScheduleId":"1602",
"availableSeats":29,
"partialCancellationAllowed":false,
"arrivalTime":"07:30 AM",
"cancellationPolicy":"[{\"cutoffTime\":\"12\",\"refundInPercentage\":\"0\"},{\"cutoffTime\":\"24\",\"refundInPercentage\":\"50\"}]",
"commPCT":0.0,
"boardingPoints":[
{
"time":"09:05PM",
"location":"Ameerpet,Kaveri Kmakshi Travels,Beside RKS Mall,Ameerpet, Mr.Aman-9391830030.",
"id":"6"
},
{
"time":"09:15PM",
"location":"Punjagutta,Sai Ganesh Travels, Punjagutta, Mr.Aman-9391830030.",
"id":"2241"
},
{
"time":"09:30PM",
"location":"Lakdi-ka-pool,Sahara Travels,Hotel Sri Krishna Complex,Mr.Aman-9391830030.",
"id":"2242"
},
{
"time":"08:45PM",
"location":"ESI,Behind Bajaj Show Room, Near Nani Travels. Mr.Aman-9391830030.",
"id":"2287"
},
{
"time":"09:45PM",
"location":"Nampally,Near Khaja Travels, Nampally,Mr.Aman-9391830030.",
"id":"2321"
},
{
"time":"09:16PM",
"location":"Paradise,Near SVR Travels, Paradise,Mr.Aman-9391830030.",
"id":"2322"
},
{
"time":"10:00PM",
"location":"Afzalgunj,Sahar Travels,Mr.Aman-9391830030.",
"id":"2323"
},
{
"time":"09:00PM",
"location":"Secunderbad Station,Near Asian Travels.Mr.Aman-9391830030.",
"id":"2336"
}
],
"droppingPoints":null,
"inventoryType":0
}
The "cancellationPolicy" element is a string which is what is called "embedded JSON". (Why they did that in this case I haven't a clue.) This means that the string must be fed through NSJSONSerialization again. And to convert the NSString to NSData (to feed through NSJSONSerialization again) you need to first use dataWithEncoding:NSUTF8StringEncoding.

Parsing values from NSArray based on JSON format

I have a NSArray which is based on JSON format. I requested it from the web and saved it in the array. I am trying to use a dictionary to get the values of "categoryname" and "subscore" and store them in new arrays, but they remain empty. Do I have to convert the array back to NSData using JSON serialisation or is there a more direct way to achieve this?
NSArray detailedscore:
{
"articles": [
{
"abstract": "text",
"title": "title"
}
],
"subscore": 3,
"categoryname": "Reporting"
},
{
"articles": [
{
"abstract": "text2",
"title": "title"
}
],
"subscore": 1,
"categoryname": "Power"
}]
}
Code:
for(int i = 0; i < [self.detailedscore count]; i++)
{
NSMutableDictionary * dc = [self.detailedscore objectAtIndex:i];
NSString * score = [dc objectForKey:#"subscore"];
NSString * categoryname = [dc objectForKey:#"categoryname"];
[self.allscores addObject:subscore];
[self.allcategories addObject:categoryname];
for (NSString *yourVar in allcategories) {
NSLog (#"Your Array elements are = %#", yourVar);
}
{} ----> means dictionary, []---> array..... this is a rule I follow while assinging the return value from webservices as NSArray or NSDictionary....
Depending on your current JSON format, perhaps this might give you an idea
NSMutableArray *categoryArray = [NSMutableArray new];
for (NSDictionary *childDict in self.detailedscore)
{
[categoryArray addObject:[childDict objectForkey:#"categoryname"]];
}
If you have the array use below code
for(int i = 0; i < [self.detailedscore count]; i++)
{
NSMutableDictionary * dc = [self.detailedscore objectAtIndex:i];
NSString * score = [dc objectForKey:#"subscore"];
NSString * categoryname = [dc objectForKey:#"categoryname"];
[self.allscores score];
[self.allcategories addObject:categoryname];
for (NSString *yourVar in allcategories) {
NSLog (#"Your Array elements are = %#", yourVar);
}
The problem wasn't in the array or dictionary or the web request. I didn't allocated the NSMutableArrays so they were empty all the time. The code works fine for extracting values from the array in case anyone wants to use it.
Hope this helps.
[NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!connectionError) {
NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&connectionError];
NSLog(#"Dict %#",dict);
BOOL isValid = [NSJSONSerialization isValidJSONObject:dict];
if (isValid) {
[target getJSONFromresponseDictionary:dict forConnection:strTag error:connectionError];
}
else{
NSString *strResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[target getStringFromresponseDictionary:strResponse forConnection:strTag error:error];
}

How to use data from one JSON request for a second JSON request?

I have been successful in parsing JSON from an API and displaying it in a tableview. The data I am receiving is a user's classes that he is enrolled in, however the data I am receiving is only the class Id's so I have to take each class ID and send a separate API request to get the class name and teacher. I am able to successfully do this on a separate view controller as I can get the class ID if the user clicks the row, however, I would like to display the class name and teacher and ID on a single table view.
So my question is, how would I get data from my table view and make a separate api request for each cell and display the data onto that cell?
My current data:
If I click a row I get this data:
2013-06-17 17:06:59.232 App[22024:c07] Class: Honors Pre-Calculus
2013-06-17 17:06:59.233 App[22024:c07] Teacher: Joe Shmo
How would I show both on one screen?
This is my code for retrieving class ids on first screen:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([searchResults count] == 0) {
return [tableView dequeueReusableCellWithIdentifier:
NothingFoundCellIdentifier];
} else {
ScheduleResultCell *cell = (ScheduleResultCell *)[tableView dequeueReusableCellWithIdentifier:SearchResultCellIdentifier];
ScheduleResult *searchResult = [searchResults objectAtIndex:indexPath.row];
NSString *classFormat = #"%#";
NSString *classfks = searchResult.class_fk;
NSString *classfk = [NSString stringWithFormat:classFormat, classfks];
cell.idLabel.text = classfk;
return cell;
}
}
This is my code for retrieving class info on second screen:
-(void)viewDidAppear:(BOOL)animated {
url = [NSString stringWithFormat:#"https://myapiurl.com/v1/classes/%#.json", idValue];
//show loader view
[SVProgressHUD showWithStatus:#"Loading Info"];
//fetch the feed
_feed = [[ClassFeed alloc] initFromURLWithString:url
completion:^(JSONModel *model, JSONModelError *err) {
//hide the loader view
[SVProgressHUD dismiss];
//json fetched
NSLog(#"Class: %#", _feed.course);
NSLog(#"Teacher: %#", _feed.teacher_full_name);
NSLog(#"Meeting Info: %#", _feed.meeting_times);
[self.tableView reloadData];
}];
}
Any idea how to accomplish this on one screen?
Here's what I've been trying to do, but it seems to only show data on one cell:
int count = [searchResults count];
NSString *classFormat = #"%#";
NSString *classfks = searchResult.class_fk;
NSString *classfk = [NSString stringWithFormat:classFormat, classfks];
for (int i=0; i < count; i++) {
ScheduleResult *classInfo = [searchResults objectAtIndex:indexPath.row];
NSString *classId = classInfo.class_fk;
NSLog(#"i value: %d", i);
url2 = [NSString stringWithFormat:#"https://apiurl.com/v1/classes/%#.json", classId];
NSLog(#"url value: %#", url2);
[SVProgressHUD showWithStatus:#"Loading Info"];
_feed = [[ClassFeed alloc] initFromURLWithString:url2
completion:^(JSONModel *model, JSONModelError *err) {
//hide the loader view
[SVProgressHUD dismiss];
//json fetched
NSLog(#"Class #%d: %#", i, _feed.course);
NSLog(#"Teacher #%d: %#", i, _feed.teacher_full_name);
NSLog(#"Meeting #%d: %#", i, _feed.meeting_times);
//name = namefk;
NSString *nameFormat = #"%#";
NSString *namefks = _feed.course;
NSString *namefk = [NSString stringWithFormat:nameFormat, namefks];
cell.nameLabel.text = namefk;
//[self.tableView reloadData];
}];
}
I tried adding my data to an array in an attempt at a different method but I can't even accomplish that correctly.
NSMutableArray* fullArray;
fullArray = [[NSMutableArray alloc] init];
[fullArray addObject:classfk];
NSLog(#"array: %#", fullArray);
Debug output:
array: ( 10326
) 2013-06-17 23:36:45.488 App[30088:c07] array: ( 10371 )
2013-06-17 23:36:45.494 App[30088:c07] array: (
10420 )
If this question doesn't make much sense, I would like to ask how I can get the class_fk from this JSON feed (first url):
[{
"class_fk": 10326,
"currently_enrolled": true,
"date_withdrawn": null,
"enrollment_pk": 147745,
"fee_paid": false,
"late_date_enrolled": null,
"level": null,
"student_fk": 132664,
"update_date": "2012-08-27"
},
{
"class_fk": 10371,
"currently_enrolled": true,
"date_withdrawn": null,
"enrollment_pk": 147168,
"fee_paid": false,
"late_date_enrolled": null,
"level": null,
"student_fk": 132664,
"update_date": "2012-08-23"
}
And use it to insert into another url and get the course and teacher_full_name from this? (second url):
{
"class_id": "ADVMTG-40",
"class_pk": 10326,
"course": "Advisor Meeting",
"course_id": 7,
"course_type": "Advisory",
"description": "ADV: Shmo, J.",
"group_fk": 13980,
"primary_grade_level": "None",
"school_level": "Upper School",
"school_year": 2012,
"status": "Active",
"subject": "Administration",
"teacher_fk": 80404,
"teacher_full_name": "Joe Shmo",
"update_date": "2012-10-23T10:06:00-05:00",
"teachers": [
{
"person_fk": 80404,
"role": "Primary Teacher",
"role_id": 1,
"teacher_name": "Joe Shmo",
"update_grades": true,
"view_grades": true
}
],
"meeting_times": [
{
"block": "Advisor Meetings",
"block_abbreviation": "ADV",
"day": "Friday",
"end_time": null,
"grading_period": "ALL",
"room": null,
"start_time": null
}
]}
Here is the solution to my problem (thanks so much for the help!):
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//[searchResults sortUsingSelector:#selector(compareName:)];
NSString *urlString = #"https://apiurl.com/v1/enrollments.json?student=132664";
NSURL *Url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:Url];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSArray *classes = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];
//NSLog(#"classes array: %#", classes);
//now we loop through all classes
for (NSMutableDictionary *class in classes) {
//we get individual data for each class
NSString *classID = class[#"class_fk"];
//NSLog(#"classID: %#", classID);
NSString *classUrlString = [NSString stringWithFormat:#"https://apiurl.com/v1/classes/%#.json", classID];
NSURL *classUrl = [NSURL URLWithString:classUrlString];
NSURLRequest *classRequest = [NSURLRequest requestWithURL:classUrl];
NSData *classData = [NSURLConnection sendSynchronousRequest:classRequest returningResponse:nil error:nil];
NSDictionary *classDictionary = [NSJSONSerialization JSONObjectWithData:classData
options:NSJSONReadingMutableContainers
error:nil];
//NSLog(#"classes dictionary: %#", classDictionary);
if (classes == nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[self showNetworkError];
});
return;
} else {
if (classDictionary == nil) {
NSLog(#"classes dictionary: %#", classDictionary);
} else {
//probably should check here if array is empty before accessing first object
//we shove the data from a classDictionary into class
//class[#"teacher_full_name"] = classDictionary[#"teacher"][0];
if (classDictionary[#"teacher_full_name"] == nil) {
class[#"teacher_full_name"] = #"Not Provided";
} else {
class[#"teacher_full_name"] = classDictionary[#"teacher_full_name"];
}
if (classDictionary[#"course"] == nil) {
class[#"course"] = #"Not Provided";
} else {
class[#"course"] = classDictionary[#"course"];
}
if (classDictionary[#"class_pk"] == nil) {
class[#"class_pk"] = #"Not Provided";
} else {
class[#"class_pk"] = classDictionary[#"class_pk"];
}
if (classDictionary[#"teachers"][0][#"person_fk"] == nil) {
class[#"person_fk"] = #"Not Provided";
} else {
class[#"person_fk"] = classDictionary[#"teachers"][0][#"person_fk"];
}
ScheduleResult *searchResult = [[ScheduleResult alloc] init];
searchResult.name = class[#"course"];
searchResult.teacher = class[#"teacher_full_name"];
searchResult.class_fk = class[#"class_pk"];
[searchResults addObject:searchResult];
NSLog(#"searchresult: %#", class[#"person_fk"]);
//NSLog(#"course: %# and teacher: %#", class[#"course"], class[#"teacher_full_name"] );
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
//NSLog(#"dictionary: %#", classes);
[self.tableView reloadData];
[SVProgressHUD dismiss];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
});
Ok there's two options here.
First is (in a background queue), get the initial feed. Then parse the JSON. Then loop through the JSON and make api call for each dictionary in the array and shove it back into the dictionary. Then tell your table to reload on the main queue.
Second option is slightly more complicated. As the user scrolls through your table, you can make a call in a background queue to get the appropriate data and update the cell. It's very similar to how images are loaded asynchronously in a cell. Except here, it's not an image but rather JSON. You should cache this data so this doesn't happen twice, and cancel the request if the user scrolls too quickly and the cell loading the data isn't on screen any more.
I suggest you stay with the first, keep it simple and easy (although maybe not as efficient because you are eager loading the data ahead of time, but if the # of records returned by the first api call is small, then it should be fine, but if it's in 100s then go with second option).
Also, it's important to note that you need to do all operations synchronously in the first option (that's how you know all data is downloaded).
Ok here's the first option. I did this with NSURLConnection. Please note that I don't like this option, but it's easy and gets the job done:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//first we get all classes
NSString *urlString = #"https://myapiurl.com/v1/classes";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSArray *classes = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];
//now we loop through all classes
for (NSMutableDictionary *class in classes) {
//we get individual data for each class
NSString *classID = class[#"class_fk"];
NSString *classUrlString = [NSString stringWithFormat:#"https://apiurl.com/v1/classes/%#.json", classID];
NSURL *classUrl = [NSURL URLWithString:classUrlString];
NSURLRequest *classRequest = [NSURLRequest requestWithURL:classUrl];
NSData *classData = [NSURLConnection sendSynchronousRequest:classRequest returningResponse:nil error:nil];
NSDictionary *classDictionary = [NSJSONSerialization JSONObjectWithData:classData
options:NSJSONReadingMutableContainers
error:nil];
//probably should check here if array is empty before accessing first object
//we shove the data from a classDictionary into class
class[#"teachers_name"] = classDictionary[#"teachers"][0];
class[#"course"] = classDictionary[#"course"];
}
//now you've got an array of dictionaries that have teachers name and course in it.
//we tell our tableview to reload the data on main queue
dispatch_async(dispatch_get_main_queue(), ^{
[someTableView reloadData];
});
});

Count how many of a certain object appear in a JSON query

I'm returning JSON with a rough structure like the one below, and I'm trying to figure out how I can count how many platforms there are (in this case, three, but could be anything from 1 to 20 or so). I've returned the JSON into an NSDictionary and am using lines such as these to retrieve the data I need:
_firstLabel.text = _gameDetailDictionary[#"results"][#"name"];
In the above case, it'll grab the name from the results section. Since there are multiple platforms, I need to construct a loop to cycle through each name inside the platforms section. Not too sure how to go about that. All help appreciated!
"results":{
"platforms":[
{
"api_detail_url":"http://",
"site_detail_url":"http://",
"id":18,
"name":"First Name"
},
{
"api_detail_url":"http://",
"site_detail_url":"http://",
"id":116,
"name":"Second Name"
},
{
"api_detail_url":"http://",
"site_detail_url":"http://",
"id":22,
"name":"Third Name"
}
],
EDIT: Here's my fetchJSON method:
- (NSDictionary *) fetchJSONDetail: (NSString *) detailGBID {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: YES];
NSString *preparedDetailURLString = [NSString stringWithFormat:#"http://whatever/format=json", detailGBID];
NSLog(#"Doing a detailed search for game ID %#", detailGBID);
NSData *jsonData = [NSData dataWithContentsOfURL: [NSURL URLWithString:preparedDetailURLString]];
_resultsOfSearch = [[NSDictionary alloc] init];
if (jsonData) {
_resultsOfSearch = [NSJSONSerialization JSONObjectWithData: jsonData
options: NSJSONReadingMutableContainers
error: nil];
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: NO];
NSString *results = _resultsOfSearch[#"number_of_page_results"];
_numberOfSearchResults = [results intValue];
NSArray *platforms = [_resultsOfSearch valueForKey:#"platforms"];
int platformsCount = [platforms count];
NSLog(#"This game has %d platforms!", platformsCount);
return _resultsOfSearch;
}
The "platforms" JSON field is an array, so assuming you've de-serialised the JSON using something like,
NSMutableDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:resultsData options:NSJSONReadingMutableContainers error:&error];
Then, you can assign platforms to an NSArray,
NSDictionary *results = [responseJSON valueForKey:#"results"];
NSArray *platforms = [results valueForKey:#"platforms"];
...and find the number of platforms via,
int platformsCount = [platforms count];
In your case, where you want to iterate through the platforms, you can use,
for (NSDictionary *platform in platforms)
{
// do something for each platform
}

Resources