Inherits from NSObject
Declared in TLIndexPathDataModel.h

Overview

TLIndexPathDataModel is an immutable object you use in your view controller to hold your data items instead of an array. Creating a data model is as easy as passing an array of items (of any type) to the initializer. Or if the data needs to be organized into sections, there are two additional initializers, one for implicitly defined sections using sectionNameKeyPath and another for an explicitly defined array of TLIndexPathSectionInfo objects. A multitude of APIs are provided for accessing the data and translating between index paths and data items.

This class can be used on it’s own to help fulfill the table or collection view data source and delegate methods. For example, the prototypically implementation of numberOfRowsInSection is:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.dataModel numberOfRowsInSection:section];
}

But the real power of TLIndexPathTools lies in use of the companion class TLIndexPathUpdates to perform animated batch udpates when items are inserted, moved or deleted from the data model. To modify the data model, one would typically either extract items from the current data model into an NSMUtableArray, make changes, and then instantiate a new data model with the updated items:

TLIndexPathDataModel *oldDataModel = self.dataModel;
NSMutableArray *items = [NSMutableArray arrayWithArray:oldDataModel.items];
... //make changes to items
self.dataModel = [TLIndexPathDataModel alloc] initWithItems:items];

//batch updates
TLIndexPathUpdates *updates = [TLIndexPathUpdates alloc] initWithOldDataModel:oldDataModel updatedDataModel:self.dataModel];
[updates performBatchUpdatesOnTableView:self.tableView withRowAnimation:UITableViewRowAnimationFade];

Another common pattern is to write a factory method for the data model that recreates the data model from scratch based current state of the view controller:

TLIndexPathDataModel *oldDataModel = self.dataModel;
self.dataModel = [self newDataModel];

//batch updates
TLIndexPathUpdates *updates = [TLIndexPathUpdates alloc] initWithOldDataModel:oldDataModel updatedDataModel:self.dataModel];
[updates performBatchUpdatesOnTableView:self.tableView withRowAnimation:UITableViewRowAnimationFade];

But the recommended approach is to use TLIndexPathController because it works interchangeably with Core Data NSFetchRequests or plain arrays of arbitrary data. Thus, it provides a unified programming model for building tables and collection views. The typical way to use TLIndexPathController is:

NSMutableArray *items = [NSMutableArray arrayWithArray:self.indexPathController.items];
... //make changes to items
self.indexPathController.items = items;

where the items property is just a shortcut for setting the dataModel property.

When the controller’s data model gets updated, the it calls its delegate methods, the primiry one being didUpdateDataModel. The typical implementation would simply perform the batch updates:

- (void)controller:(TLIndexPathController *)controller didUpdateDataModel:(TLIndexPathUpdates *)updates
{
    [updates performBatchUpdatesOnTableView:self.tableView withRowAnimation:UITableViewRowAnimationFade];
}

When working with Core Data, the main differences is that you’d initialize the TLIndexPathController with an NSFetchRequest and then the data model get generated/updated internally as the fetch results change.

Another advantage in using TLIndexPathController is that you can define base table and collection view controller classes and use them everywhere (i.e. with or without Core Data). TLIndexPathTools provides two such implementations: TLTableViewController and TLCollectionViewController. Both classes provide default implementations of the essential data source and delegate methods to get you up-and-running quickly. TLTableViewController also provides a default implementation of heightForRowAtIndexPath that can handle custom cell heights (static heights defined in Interface Builder or dynamic heights defined by implementing the TLDynamicSizeView protocol in a custom cell class).

Item Identification

TLIndexPathDataModel needs to be able to identify items in order to keep an internal mapping between items and index paths and to track items across versions of the data model. It does not assume that the item itself is a valid identifier (for example, if the item doesn not implement NSCopying, it cannot be used as a dictionary key). So the following set of rules are used to locate a valid identifier. Each rule is tried in turn until a non-nil value is found:

  1. If identifierKeyPath is specified (through an appropriate initializer), the data model attempts to use the item’s value for this key path. If the key path is invalid for the given item, the next rule is tried.
  2. If the item is an instance of TLIndexPathItem, the value of the identifier property is tried.
  3. If the item is an instance of NSManagedObject, the objectID property is used.
  4. If the item conforms to NSCopying, the item itself is used.
  5. If all else fails, the item’s memory address is returned as a string.

Section Name Identifcation

TLIndexPathDataModel identifies sections by their name, which is defined according to the following rules.

  1. If sectionNameKeyPath is specified (through the appropriate initializer), the data model attempts to use the item’s value for this key path. If the key path is invalid for the given item, the next rule is tried.
  2. If the item is an instance of TLIndexPathItem, the value of the sectionName property is tried.
  3. The value TLIndexPathDataModelNilSectionName is used.

Properties

identifierKeyPath

The key path used to identify items. Identifier key paths can be used when the item itself is not a suitable identifier (see Item Identification). An example is when the data model contains raw JSON data (dictionaries). In order to refresh the data, a new JSON response will contain new dictionary items. Without an identifier key path, it will not be possible to identify items across data models if any of the data has changed (due to the way [NSDictionary isEqual] works). However, JSON data items typically contain a key field, such as “recordId”, that identifies the item. By setting the identifierKeyPath to this key field, TLIndexPathTools will be able to track items across data models.

@property (strong, nonatomic, readonly) NSString *identifierKeyPath

Declared In

TLIndexPathDataModel.h

indexPaths

An array containing all index paths.

@property (strong, nonatomic, readonly) NSArray *indexPaths

Declared In

TLIndexPathDataModel.h

items

An array containing all items.

@property (strong, nonatomic, readonly) NSArray *items

Declared In

TLIndexPathDataModel.h

numberOfSections

The number of sections in the data model.

@property (nonatomic, readonly) NSInteger numberOfSections

Declared In

TLIndexPathDataModel.h

sectionNameKeyPath

The key path used to identify an item’s section. If specified in the relevant initializer, the data model items will be organized into sections according to the value of the their sectionNameKeyPath. Unlike NSFetchedResultsController, items do not need to be presorted by section.

@property (strong, nonatomic, readonly) NSString *sectionNameKeyPath

Declared In

TLIndexPathDataModel.h

sectionNames

The array of section names in the data model. If the model has been initialized without any explicit sections, this array will contain the single name TLIndexPathDataModelNilSectionName. Note that section names are unique. See Section Names.

@property (strong, nonatomic, readonly) NSArray *sectionNames

Declared In

TLIndexPathDataModel.h

sections

The array of TLIndexPathSectionInfo objects organizing the data into sections. TLIndexPathSectionInfo is an implementation of the NSFetchedResultsSectionInfo protocol.

@property (strong, nonatomic, readonly) NSArray *sections

Declared In

TLIndexPathDataModel.h

title

The title of the data model. Can be used to store a value for the view controller’s title property. This property will be removed in a later version.

@property (strong, nonatomic) NSString *title

Declared In

TLIndexPathDataModel.h

Instance Methods

containsItem:

Retuns YES if the data model contains the given item.

- (BOOL)containsItem:(id)item

Parameters

item

the specified item

Declared In

TLIndexPathDataModel.h

currentVersionOfItem:

Returns the current version of the given item. This method can be useful in scenarios where different versions of the data model contain different instances representing the same items. Note that this method is just a shortcur for calling identifierForItem: followed by itemForIdentifier:.

- (id)currentVersionOfItem:(id)anotherVersionOfItem

Parameters

anotherVersionOfItem

the specified item from a different version of the data model.

Declared In

TLIndexPathDataModel.h

identifierAtIndexPath:

Returns the item identifier at the given index path. Returns nil for an invalid index path.

- (id)identifierAtIndexPath:(NSIndexPath *)indexPath

Parameters

indexPath

the specified index path

Declared In

TLIndexPathDataModel.h

identifierForItem:

Returns the identifier for the given item. Returns nil if the item is not a member of the data model.

- (id)identifierForItem:(id)item

Parameters

item

the specified item

Declared In

TLIndexPathDataModel.h

indexPathForIdentifier:

Returns the index path for the given identifier. Returns nil for an invalid identifier.

- (NSIndexPath *)indexPathForIdentifier:(id)identifier

Parameters

identifier

the specified identifier

Declared In

TLIndexPathDataModel.h

indexPathForItem:

Returns the index path for the given item. Returns nil if the item is not a member of the data model.

- (NSIndexPath *)indexPathForItem:(id)item

Parameters

item

the specified item

Declared In

TLIndexPathDataModel.h

initWithItems:

The basic initializer.

- (id)initWithItems:(NSArray *)items

Parameters

items

the itmes that make up the data model

Discussion

This initializer can only organize data into a single section and use the default item identification rules. Use one of the other initializers if you need multiple sections or need to specify an identifierKeyPath. An exception to this if your items are instance of the TLIndexPathItem wrapper class since the data model is aware of, and will make use of the buit in identifier and sectionName properties.

Declared In

TLIndexPathDataModel.h

initWithItems:sectionNameBlock:identifierBlock:

Use this initializer to organize sections and identify items using blocks. This can be used, for example, to organize a list of strings into sections based on the first letter of the string (similar to the Contacts app).

- (id)initWithItems:(NSArray *)items sectionNameBlock:(NSString *( ^ ) ( id item ))sectionNameBlock identifierBlock:(id ( ^ ) ( id item ))identifierBlock

Parameters

items

the itmes that make up the data model

sectionNameBlock

block that returns the section name for the given item Note that items do not need to be pre-sorted. Specifying nil will result in a single section named TLIndexPathDataModelNilSectionName.

identifierBlock

block that returns the identifier for the given item. Specifying nil will result in the default object identification rules being used.

Declared In

TLIndexPathDataModel.h

initWithItems:sectionNameKeyPath:identifierKeyPath:

Use this initializer to organize sections by the item sectionNameKeyPath property or to identify items by their identifierKeyPath property.

- (id)initWithItems:(NSArray *)items sectionNameKeyPath:(NSString *)sectionNameKeyPath identifierKeyPath:(NSString *)identifierKeyPath

Parameters

items

the itmes that make up the data model

sectionNameKeyPath

the item key path to use for orgnizing data into sections. Note that items do not need to be pre-sorted by sectionNameKeyPath. Specifying nil will result in a single section named TLIndexPathDataModelNilSectionName.

identifierKeyPath

the item key path to use for identification. Specifying nil will result in the default object identification rules being used.

Declared In

TLIndexPathDataModel.h

initWithSectionInfos:identifierKeyPath:

Use this initializer to explicitly specify sections by providing an array of TLIndexPathSectionInfo objects. This initializer can be used to generate empty sections (by creating an empty TLIndexPathSectionInfo object).

- (id)initWithSectionInfos:(NSArray *)sectionInfos identifierKeyPath:(NSString *)identifierKeyPath

Parameters

sectionInfos

the section info objects that make up the data model

identifierKeyPath

the item key path to use for identification. Specifying nil will result in the default object identification rules being used.

Declared In

TLIndexPathDataModel.h

itemAtIndexPath:

Returns the item at the given index path. Returns nil for an invalid index path.

- (id)itemAtIndexPath:(NSIndexPath *)indexPath

Parameters

indexPath

the specified index path

Declared In

TLIndexPathDataModel.h

itemForIdentifier:

Returns the item for the given identifier. Returns nil for an invalid identifier.

- (id)itemForIdentifier:(id)identifier

Parameters

identifier

the specified identifier

Declared In

TLIndexPathDataModel.h

numberOfRowsInSection:

The number of rows in the specified section. Returns NSNotFound for an invalid section.

- (NSInteger)numberOfRowsInSection:(NSInteger)section

Parameters

section

the specified section index

Declared In

TLIndexPathDataModel.h

sectionForSectionName:

The section number for the given section name. Returns NSNotFound for an invalid section name.

- (NSInteger)sectionForSectionName:(NSString *)sectionName

Parameters

sectionName

the specified section name

Declared In

TLIndexPathDataModel.h

sectionInfoForSection:

Returns the TLIndexPathSectionInfo object for the given section. Returns nil for an invalid section.

- (id<NSFetchedResultsSectionInfo>)sectionInfoForSection:(NSInteger)section

Parameters

section

the specified section index

Declared In

TLIndexPathDataModel.h

sectionNameForSection:

The unique name for the givne section. Returns nil for an invalid section.

- (NSString *)sectionNameForSection:(NSInteger)section

Parameters

section

the specified section index

Declared In

TLIndexPathDataModel.h

sectionTitleForSection:

Currently returns section name.

- (NSString *)sectionTitleForSection:(NSInteger)section

Parameters

section

the specified section index

Declared In

TLIndexPathDataModel.h