Assignment #4 Extra Task #1

Please note, this blog entry is from a previous course. You might want to check out the current one.

Divide your list of top places into sections (in the table view sense) by country. This will require a little bit different data structure in that MVC.

To sort our places into countries we need two new properties for the data model. placesByCountry will hold the places separated into their countries. countries will just hold the names of the countries sorted alphabetically.

@property (nonatomic, strong) NSDictionary *placesByCountry;
@property (nonatomic, strong) NSArray *countries;
@synthesize placesByCountry = _placesByCountry;
@synthesize countries = _countries;

When places are set (in the places setter) we will call a new function which loops over the places. If country does not exist yet, it will be created, then we add the place to its country.
Afterwards we sort the country array alphabetically.

- (void)updatePlacesByCountry
    NSMutableDictionary *placesByCountry = [NSMutableDictionary dictionary];
    for (NSDictionary *place in self.places) {
        NSString *country = [FlickrData countryOfPlace:place];
        NSMutableArray *places = [placesByCountry objectForKey:country];
        if (!places) {
            places = [NSMutableArray array];
            [placesByCountry setObject:places forKey:country];
        [places addObject:place];
    self.placesByCountry = placesByCountry;
    NSArray *countries = [placesByCountry allKeys];
    self.countries = [countries sortedArrayUsingComparator:^(id a, id b) {
        return [a compare:b options:NSCaseInsensitiveSearch];

To simplify the code above we added a new function to the FlickrData class:

+ (NSString *)countryOfPlace:(NSDictionary *)place
    return [[[place objectForKey:FLICKR_PLACE_NAME] 
             componentsSeparatedByString:@", "] lastObject];    

Back in the top-places table view controller class, set the number of sections to the number of countries:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    return [self.countries count];

and set the title of the section:

- (NSString *)tableView:(UITableView *)tableView 
    return [self.countries objectAtIndex:section];

The number of rows inside each section is set by looking into each section separately. First we lookup the country name for a section and then fetch the respective places:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    return [[self.placesByCountry objectForKey:
             [self.countries objectAtIndex:section]] count];

Same happens when populating the cells – only the variable names are slightly different:

    NSDictionary *place = [[self.placesByCountry objectForKey:
                            [self.countries objectAtIndex:indexPath.section]
                            ] objectAtIndex:indexPath.row];

Finally prepareForSegue has to be adjusted to lookup sections and rows:

        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        [segue.destinationViewController setPlace:
         [[self.placesByCountry objectForKey:
           [self.countries objectAtIndex:indexPath.section]
           ] objectAtIndex:indexPath.row]];

The complete code for this task is available at github.


Leave a Reply

Your email address will not be published.