TLIndexPathDataModel Class Reference
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:
- 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. - If the item is an instance of
TLIndexPathItem
, the value of theidentifier
property is tried. - If the item is an instance of
NSManagedObject
, theobjectID
property is used. - If the item conforms to
NSCopying
, the item itself is used. - 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.
- 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. - If the item is an instance of
TLIndexPathItem
, the value of thesectionName
property is tried. - The value TLIndexPathDataModelNilSectionName is used.
Tasks
Creating data models
-
– initWithItems:
-
– initWithItems:sectionNameKeyPath:identifierKeyPath:
-
– initWithItems:sectionNameBlock:identifierBlock:
-
– initWithSectionInfos:identifierKeyPath:
Data model configuration
-
identifierKeyPath
property -
sectionNameKeyPath
property
Data model content
-
title
property -
numberOfSections
property -
sectionNames
property -
sections
property -
items
property -
indexPaths
property -
– numberOfRowsInSection:
-
– sectionNameForSection:
-
– sectionForSectionName:
-
– sectionTitleForSection:
-
– sectionInfoForSection:
-
– itemAtIndexPath:
-
– identifierAtIndexPath:
-
– containsItem:
-
– indexPathForItem:
-
– indexPathForIdentifier:
-
– identifierForItem:
-
– itemForIdentifier:
-
– currentVersionOfItem:
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
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 namedTLIndexPathDataModelNilSectionName
.
- 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 namedTLIndexPathDataModelNilSectionName
.
- 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