I have been trying for days to figure out how to parse this JSON to a sectioned UITable but I am not successful, I've only been able to figure out how to get the section name, but failed to get each section row count and data for each row in each section.
Since the transportation group may vary from time to time and their name may change, so I guess I need to use allKeys to find out each section title 1st.
Please help and points me to the right direction to extract the data for a sectioned UITable, Thank you.
{
"transport" : {
"public" : [
{
"transport_id" : "2",
"transport_name" : "Ferry"
},
{
"transport_id" : "3",
"transport_name" : "Bus"
},
{
"transport_id" : "4",
"transport_name" : "Taxi"
},
{
"transport_id" : "5",
"transport_name" : "Tram"
}
],
"Private" : [
{
"transport_id" : "11",
"transport_name" : "Bicycle"
},
{
"transport_id" : "12",
"transport_name" : "Private Car"
}
],
"Misc" : [
{
"transport_id" : "6",
"transport_name" : "By Foot"
},
{
"transport_id" : "7",
"transport_name" : "Helicopter"
},
{
"transport_id" : "8",
"transport_name" : "Yatch"
}
]
}
}
NSDictionary *results = [jsonString JSONValue];
NSDictionary *all = [results objectForKey:@"transport"];
NSArray *allKeys = [all allKeys];
NSArray *transports = [results objectForKey:@"transport"];
for (NSDictionary *transport in transports)
{
[transportSectionTitle addObject:(transport)];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [transportSectionTitle count];
}
The easiest solution to explain is to use the all
dictionary as your datasource.
NSDictionary *results = [jsonString JSONValue];
NSDictionary *all = [results objectForKey:@"transport"];
// self.datasource would be a NSDictionary retained property
self.datasource = all;
Then to get the number of sections you could do :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.datasource count]; // You can use count on a NSDictionary
}
To get the title of the sections:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = [[self.datasource allKeys] objectAtIndex:section];
return title;
}
To get the number of rows in each section:
- (NSInteger)tableView:(UITableView *)favTableView numberOfRowsInSection:(NSInteger)section {
// Get the all the transports
NSArray *allTransports = [self.datasource allValues];
// Get the array of transports for the wanted section
NSArray *sectionTransports = [allTransports objectAtIndex:section];
return [sectionTransports count];
}
Then to get the rows :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Get the all the transports
NSArray *allTransports = [self.datasource allValues];
// Get the array of transports for the wanted section
NSArray *sectionTransports = [allTransports objectAtIndex:indexPath.section];
// Then get the transport for the row
NSDictionary *transport = [sectionTransports objectAtIndex:indexPath.row];
// Now you can get the name and id of the transport
NSString *tansportName = [transport objectForKey:@"transport_name"];
NSString *transportId = [transport objectForKey:@"transport_id"];
NSString *transportDescription = [NSString stringWithFormat:@"%@ - %@",transportId, transportName];
cell.textLabel.text = transportDescription;
return cell;
}
That's the gist of it anyway.
You might want to store the allKeys
and allValues
arrays as class properties instead of having to go through them in all the tableview's delegate and datasource methods, but you should have all the info to build yuor table now.
Hope this helps :)
The key to what you need to do is recognizing that once your JSON string gets parsed into an object it becomes a series of nested NSArrays and NSDictionarys, and you just need to drilling through the values appropriately
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[transports allKeys] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [(NSArray*)[transports objectForKey:[[transports allKeys] objectAtIndex:section]] count];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return [transports allKeys];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// get transport category (e.g."public")
NSString *transportCategory = (NSString*)[[transports allKeys] objectAtIndex:[indexPath section]];
// get transport items belonging to the category
NSArray *items = (NSArray*)[transports objectForKey:transportCategory];
// get transport item for this row
NSDictionary *transportItem = [items objectAtIndex:[indexPath row]];
// extract values of transport item
NSString *transportName = [transportItem objectForKey:@"transport_name"];
NSString *transportID = [transportItem objectForKey:@"transport_id"];
cell.textLabel.text = transportName;
return cell;
}
NSDictionary *results = [jsonString JSONValue];
NSDictionary *allTypes = [results objectForKey:@"transport"];
NSArray *allTransportKeys = [allTypes allKeys];
Number of sections:
NSInteger numberOfSections = [allKeys count];
Number of rows in section:
NSString *key = [allKeys objectAtIndex:section];
NSArray *array = [allTypes objectForKey:key];
NSInteger numberOfRows = [array count];
Data at indexPath:
NSString *key = [allKeys objectAtIndex:indexPath.section];
NSArray *array = [allTypes objectForKey:key];
NSDictionary *itemDict = [array objectAtIndex:indexPath.row];
Then you can extract the data from itemDict.