TLIndexPathTools is a set of components designed to greatly simplify the building of rich, dynamic table and collection views. Some awesome things you can do with TLIndexPathTools include:
- Automatically calculate and perform animated batch updates
- Perform animated sorting and filtering operations against an array or
NSFetchRequest
- Easily manage multiple cell prototypes and/or multiple data types as the data model changes
The central component of TLIndexPathTools is the TLIndexPathController
class. This class
is a lot like Core Data's NSFetchedResultsController
class in that it is responsible
for tracking a data source and reporting changes to the client. The big difference is that, while
TLIndexPathController
does support NSFetchRequest
, it does not require Core Data at all.
TLIndexPathController
can just as easily work with an array of strings. For example, you can
initialize a TLIndexPathController
with an array of strings to display as table rows and then
give the controller a new array of strings (perhaps a filtered or sorted version of the
original array) and the table will automatically animate to the new state.
See the "Shuffle" example project.
TLIndexPathTools provides base view controller classes TLTableViewController
and
TLCollectionViewController
(for table and collection views, respectively) that implement the
essential delegate methods to get you up-and-running as quickly as possible.
- Download the TLIndexPathTools project
- Add the TLIndexPathTools sub-folder (sibling of the Examples folder) to your Xcode project.
- Link to QuartzCore.framework and CoreData.framework (on the Build Phases tab of your project's target).
The basic usage is as follows:
#import <UIKit/UIKit.h>
#import "TLIndexPathController.h"
@interface ViewController : TLTableViewController
@end
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexPathController.items = @[@"Chevrolet", @"Bubble Gum", @"Chalkboard"]];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
NSString *title = [self.indexPathController.dataModel itemAtIndexPath:indexPath];
cell.textLabel.text = title;
return cell;
}
This yields a table view with rows "Chevrolet", "Bubble Gum" and "Chalkboard". Note that by default, as in this example, TLIndexPathTools assumes the cell's reuse identifier is "Cell".
Things get interesting when we add dynamic behavior, such as a method that shuffles rows (which we can wire into a button):
- (IBAction)shuffle
{
NSMutableArray *shuffledItems = [NSMutableArray arrayWithArray:self.indexPathController.items];
NSInteger count = shuffledItems.count;
for (int i = 0; i < count; i++) {
[shuffledItems exchangeObjectAtIndex:i withObjectAtIndex:arc4random() % count];
}
self.indexPathController.items = shuffledItems;
}
Thats all it takes to generate a nice, smooth animated shuffle effect. Try running the Shuffle sample project to see the same effect in action with a UICollectionView
.
Now, lets pull back the curtain a bit and see what this looks like without the help of TLTableViewController
. Here is what the app looks like when done as a direct subclass of UITableViewController
(unchanged lines are gray):
#import <UIKit/UIKit.h>
#import "TLIndexPathController.h"
@interface ViewController : UITableViewController
@property (strong, nonatomic) TLIndexPathController *indexPathController;
@end
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexPathController = [[TLIndexPathController alloc] init];
self.indexPathController.items = @[@"Chevrolet", @"Bubble Gum", @"Chalkboard"]];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.indexPathController.dataModel.numberOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.indexPathController.dataModel numberOfRowsInSection:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
NSString *title = [self.indexPathController.dataModel itemAtIndexPath:indexPath];
cell.textLabel.text = title;
return cell;
}
- (IBAction)shuffle
{
NSMutableArray *shuffledItems = [NSMutableArray arrayWithArray:self.indexPathController.items];
NSInteger count = shuffledItems.count;
for (int i = 0; i < count; i++) {
[shuffledItems exchangeObjectAtIndex:i withObjectAtIndex:arc4random() % count];
}
self.indexPathController.items = shuffledItems;
}
#pragma mark - TLIndexPathControllerDelegate
- (void)controller:(TLIndexPathController *)controller didUpdateDataModel:(TLIndexPathUpdates *)updates
{
[updates performBatchUpdatesOnTableView:self.tableView withRowAnimation:UITableViewRowAnimationFade];
}
@end
As you can see, TLTableViewController
is just adding some simple boiler plate methods. It is completely fine to not use TLTableViewController
or TLCollectionViewController
, though the former does provide some nice bells and whistles like automatic (dynamic) row height calculations (see the Dynamic Height sample project).
Now lets step through the code for a brief introduction to some basic APIs.
###TLIndexPathController
@interface ViewController : UITableViewController
@property (strong, nonatomic) TLIndexPathController *indexPathController;
@end
TLIndexPathController
is the primary API access point, so we have a public property to get or set a controller. If you're familiar with Core Data's NSFetchedResultsController
, TLIndexPathController
plays a similar role except that it work with regular arrays. It also works with Core Data and can do things that NSFetchedResultsController
can't do, such as animated sorting and filtering (more on that later).
Both TLTableViewController
and TLCollectionViewController
provide default index path controllers, but it is normal to replace this instance with a custom one (see the selection of initializers in TLIndexPathController.h).
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexPathController = [[TLIndexPathController alloc] init];
self.indexPathController.items = @[@"Chevrolet", @"Bubble Gum", @"Chalkboard"]];
}
Here we create a default index path controller just as TLTableViewController
does. Then we populate the controller with our data by setting the items
array property. Data items can be any type of object from NSString
s as we have here to NSDictionarie
s (see the JSON sample project) to NSManagedObject
s (see the Core Data sample project).
###TLIndexPathDataModel
TODO...