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?
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.