Dynamic titles for sections in UITableView
I want to make a tableview containing our stores - sectioned by city.
The data for the tableview is collected thru my webapp's API in a json string which I parse to a NSDictionary using the opensource Objective-c JSON framework.
The response looks a bit like this:
{
city = "Amsterdam";
code = erbur;
title = "Shop Lorem";
},
{
city = "Amsterdam";
code = kadap;
title = "Shop Ipsum";
},
{
city = "Rotterdam";
code = elaml;
title = "Shop Dolor";
},
{
city = "Delft";
code = lamla;
title = "Shop Sit";
},
{
city = "Rotterdam";
code = koppa;
title = "Shop Amet";
},
My initial plan was to create one array per city, store those arrays in a dictionary and than, when naming the sections with titleForHeaderInSection:
do something like this:
if (section == 0) {
return @"Amsterdam"; }
else if (section == 1) {
return @"Roteterdam";
} Etc..
Here's the problem: We are expanding quite rapidly and I don't want to update my app everytime we open a shop in a new city. So I can't hardcode the arrays for the cities.
What would be the right way to make sure that new stores in new cities are displayed in the table view within the right city?
Thanks in advance!
EDIT Here's my code:
- (void)getLocData
{
SBJSON *parser = [[SBJSON alloc] init];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://foo.bar/locaties/lijst"]];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *statuses = [parser objectWithString:json_string error:nil];
//the abive works
[statusesArray release];
statusesArray = statuses;
NSArray *cityNames = [statuses valueForKey:@"code"];
[locationCodes release];
locationCodes = cityNames;
- (void)viewDidLoad {
[super viewDidLoad];
[sel开发者_StackOverflowf getLocData];
//titel
self.title = NSLocalizedString(@"Locaties", @"Locaties - Steden");
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [locationCodes count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [locationCodes objectAtIndex:section];
}
// Customize the appearance of table view cells.
- (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];
}
// Configure the cell...
NSString *cityName = [locationCodes objectAtIndex:[indexPath section]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"code like %@", cityName];
NSArray *filteredShops = [statusesArray filteredArrayUsingPredicate:predicate];
NSDictionary *currentShop = [filteredShops objectAtIndex:[indexPath row]];
NSString *cellTitle = [currentShop objectForKey:@"title"];
cell.textlabel.text = cellTitle;
return cell;
}
It looks as though your data ends up being an array of dictionaries. If that's the case you can obtain an array of city names as follows:
// Assuming you've stored the array in a variable named shops...
NSArray *cityNames = [shops valueForKey:@"city"];
So your tableView:numberOfSections:
implementation could simply return a count of that array, and similarly tableView:titleForHeaderInSection:
could just return the object in cityNames
indexed by the section number.
In tableView:cellForRowAtIndexPath:
, you could then filter the array using an instance of NSPredicate
:
NSString *cityName = [cityNames objectAtIndex:[indexPath section]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"city like %@", cityName];
NSArray *filteredShops = [shops filteredArrayUsingPredicate:predicate];
NSDictionary *currentShop = [filteredShops objectAtIndex:[indexPath row]];
EDIT
Assuming you just wanted to display each shop's title, all you'd need is the following:
NSString *title = [currentShop objectForKey:@"title"];
// Assuming you've already obtained the cell...
[[cell textLabel] setText:title];
This is off the top of my head but once you have the data in an NSDictionary you could sort it into an NSSet and sort that alphabetically. Assumptions:
- you are listing sections in alphabetical order
- the library you refer to returns an NSArray of NSDictionaries
- the keys are the names, e.g. "city" "code" "title"
Right the data really needs to be an NSArray or NSSet of NSDictionary objects. If so this works:
NSMutableSet *sectionsSet = [[NSMutableSet alloc] init];
for (NSDictionary *item in data) {
NSDictionary *aLocation = [[NSDictionary alloc] initWithObjectsAndKeys:[item valueForKey:@"city"],@"city",nil];
[sectionsSet addObject:aLocation];
[aLocation release];
}
NSSortDescriptor *sortAscending = [[NSSortDescriptor alloc] initWithKey:@"city" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortAscending,nil];
NSArray *sortedSections = [[sectionsSet allObjects] sortedArrayUsingDescriptors:sortDescriptors];
[sortDescriptors release];
[sortAscending release];
The above is tested with a dummy NSArray of NSDictionary. I think by adding the objects to an NSDictionary you avoid having to create your own NSSortDescriptor.. :/ I'll try to check this code later and update if it's broken.
The titleForHeaderInSection code would then be simply:
return [sortedSections objectAtIndex:section];
Seeing as the the cities are now sorted alphabetically the above code would return them in that order. for your example it would give three sections:
0 == Amsterdam 1 == Delft 2 == Rotterdam
The simplest way to retrieve the row you need for the section/cell in question is to ensure your NSArray is sorted correctly in the first place.
Of course you'd need to have changed the code that does the sorting to assign the created data to a class property rather than the locally created sortedSections I used in the example.
Caveats:
- The sort is case sensitive, irregularities in data will produce problems. Amsterdam != amsterdam != aMsterdam etc.
精彩评论