Search code examples
iosnsarraynsdictionaryconceptual

How should I ideally create a well-structured UITableViewDataSource?


I have an NSArray of songs fetched from a server. That is my raw data source. The array contains custom objects which have an NSDictionary and NSArray as backend.

I am wondering if implementing a formatted data source using an NSDictionary will be wise. The dictionary will have section headers as keys, and the value of a certain key will have an NSArray containing the rows for that section.

I will be iterating through my raw data source and arranging it alphabetically into the dictionary.

I have a feeling that this is not a solid implementation and is very expensive. Is there any other, more solid implementation than this?


Solution

  • For small tables, rather than NSDictionary, I generally use NSArray, since dictionaries don't preserve order (and you probably don't want to continually re-sort). So I usually have an array of sections, for which I have for each section entry, at the very least, a section title and an array of rows. My array of rows has, that information that I need to present a given row (e.g. the text of the row, etc.).

    The individual row and section objects, you can implement those as a NSDictionary objects themselves (and sometimes when parsing the data from JSON or XML, that's easiest), but I generally define my own Row and Section objects, e.g.:

    @interface Row : NSObject
    
    @property (nonatomic, strong) NSString *title;
    @property (nonatomic, strong) NSString *subtitle;
    
    @end
    

    and

    @interface Section : NSObject
    
    @property (nonatomic, strong) NSString *title;
    @property (nonatomic, strong) NSMutableArray *rows;
    
    @end
    

    Then my table view controller has an NSArray for the sections:

    @property (nonatomic, strong) NSMutableArray *sections;
    

    And I populate it like so:

    self.sections = [NSMutableArray array];
    
    Section *sectionObject;
    
    sectionObject = [[Section alloc] initWithTitle:@"Marx Brothers" rows:nil];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Chico"   subtitle:@"Leonard Marx"]];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Harpo"   subtitle:@"Adolph Marx"]];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Groucho" subtitle:@"Julius Henry Marx"]];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Zeppo"   subtitle:@"Herbert Manfred Marx"]];
    [self.sections addObject:sectionObject];
    
    sectionObject = [[Section alloc] initWithTitle:@"Three Stooges" rows:nil];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Moe"   subtitle:@"Moses Harry Horwitz"]];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Larry" subtitle:@"Louis Feinberg"]];
    [sectionObject.rows addObject:[[Row alloc] initWithTitle:@"Curly" subtitle:@"Jerome Lester \"Jerry\" Horwitz"]];
    [self.sections addObject:sectionObject];
    

    And then I have the typical UITableViewDataSource methods:

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [self.sections count];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        Section *sectionObject = self.sections[section];
        return [sectionObject.rows count];
    }
    
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        Section *sectionObject = self.sections[section];
        return sectionObject.title;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    
        Section *sectionObject = self.sections[indexPath.section];
        Row *rowObject = sectionObject.rows[indexPath.row];
    
        cell.textLabel.text = rowObject.title;
        cell.detailTextLabel.text = rowObject.subtitle;
    
        return cell;
    }
    

    For bigger, database data driven tables, I might not keep the data in arrays, but rather use Core Data or SQLite, but the idea is the same. Make sure I have Section and Row classes that keep my table view controller code self-explanatory and insulated from the details of the data implementation.