TLIndexPathTools
TLIndexPathTools 是一组可以提高您的表格和集合视图操作的类库。以下是 TLIndexPathTools 能做的几件令人印象深刻的事情:
- 轻松地将数据组织到分区(现在有块功能!)
- 计算和执行动画批量更新(插入、移动和删除)
- 通过丰富的数据模型 API 简化数据源和代理方法
- 提供对 Core Data
NSFetchedResultsController
的更简单替代品 - 提供具有高级功能的基类表视图和集合视图
TLIndexPathTools 的轻量级程度由您决定。通过使用 TLIndexPathDataModel
作为您的数据模型(而不是数组)开始,可以轻松组织数据到分区,并通过像 [dataModel numberOfRowsInSection:]
、[dataModel itemAtIndexPath:]
和 [dataModel indexPathForItem:]
这样的 API 简化视图控制器。或者继续阅读,了解自动批量更新、更简单的 Core Data 集成等。
安装
将 "TLIndexPathTools" 添加到您的 podfile 中,或者如果您没有使用 CocoaPods
- 下载 TLIndexPathTools 项目
- 将 TLIndexPathTools 子文件夹(与 Examples 文件夹同级)添加到您的 Xcode 项目中。
- 链接到 QuartzCore.framework 和 CoreData.framework(在项目目标的“构建设置”选项卡中)。
概览
NSArray
是用于简单表格和集合视图数据模型的标准化结构。然而,如果涉及多个部分,典型的设置是一个包含部分名称的 NSArray
以及一个以部分名称为键的包含数据项 NSArrays
的 NSDictionary
。由于表格和集合视图与 NSIndexPath
一起工作,因此在数据源和代理方法中反复使用以下模式:
NSString *sectionName = self.sectionNameArray[indexPath.section];
NSArray *sectionArray = self.sectionArraysBySectionName[sectionName];
id data = sectionArray[indexPath.row];
TLIndexPathDataModel
将此模式封装到单个类中,并提供许多API以简化数据访问。此外,TLIndexPathDataModel
初始化器提供多种组织原始数据为部分的途径(包括空部分)。TLIndexPathDataModel
非常适合单部分视图,在此处 NSArray
就足够了,并且在以后添加额外部分时具有“重构证明”的好处。
TLIndexPathUpdates
是与 TLIndexPathDataModel
配对的一个非常强大的类。表格和集合视图的出色之处之一是它们能够执行批更新(插入、删除和移动),以平滑地移动细胞在状态之间。然而,当涉及多个更新时,计算批更新可能是一个复杂(并且令人困惑)的任务。TLIndexPathUpdates
通过获取您数据模型的两个版本,为您计算更改,并自动执行批更新来解决这个问题。
TLIndexPathTools 中的大多数功能都可以仅使用 TLIndexPathDataModel
和 TLIndexPathUpdates
完成。但是,还有一些额外的组件提供了一些很棒的功能
TLIndexPathController
提供了一个共同的编程模型,用于构建与 Core DataNSFetchRequest
或任何数据类型的普通数组协同工作的视图控制器。一个控制器可以统治所有。TLTableViewController
和TLCollectionViewController
是表格和集合视图的基类,它们使用TLIndexPathController
并实现基本的数据源和代理方法,以快速启动和运行。它们还支持由视图控制器支持的单元格(请参阅View Controller Backed 示例项目)以及表格的自动单元格高度计算(请参阅Dynamic Height 示例项目)。TLIndexPathItem
是一个包装数据项的类,可以简化使用多种数据类型或单元格类型的工作。例如,查看设置示例项目。- “Extensions” 文件夹包含有关例如可折叠部分 和 可展开树视图 的插件。这是一个非常好的资源,了解如何轻松扩展
TLIndexPathDataModel
以适用于特殊数据结构。 - 最后但同样重要的是,“Examples” 文件夹包含许多示例项目,展示了框架的各种用例和功能。Shuffle 是一个好的起点,并确保尝试Core Data。
此版本的 TLIndexPathTools 旨在处理多达几千个项目。较大的数据集可能会有性能问题。
TLIndexPathDataModel
TLIndexPathDataModel
是一个不可变对象,您可以在视图控制器中使用它来保存数据项,而不是使用数组(或数组的字典,用于多个分区)。它有四个初始化器,一个基本的和一个处理多个分区的三个初始化器。
// single section initializer
TLIndexPathDataModel *dataModel1 = [[TLIndexPathDataModel alloc] initWithItems:items];
// multiple sections defined by a key path property on your data items
TLIndexPathDataModel *dataModel2 = [[TLIndexPathDataModel alloc] initWithItems:items sectionNameKeyPath:@"someKeyPath" identifierKeyPath:nil];
// multiple sections defined by an arbitrary code block
TLIndexPathDataModel *dataModel3 = [[TLIndexPathDataModel alloc] initWithItems:items sectionNameBlock:^NSString *(id item) {
// organize items by first letter of description (like contacts app)
return [item.description substringToIndex:1];
} identifierBlock:nil];
// multiple explicitly defined sections (including an empty section)
TLIndexPathSectionInfo *section1 = [[TLIndexPathSectionInfo alloc] initWithItems:@[@"Item 1.1"] name:@"Section 1"];
TLIndexPathSectionInfo *section2 = [[TLIndexPathSectionInfo alloc] initWithItems:@[@"Item 2.1", @"Item 2.2"] name:@"Section 2"];
TLIndexPathSectionInfo *section3 = [[TLIndexPathSectionInfo alloc] initWithItems:nil name:@"Section 3"];
TLIndexPathDataModel *dataModel4 = [[TLIndexPathDataModel alloc] initWithSectionInfos:@[section1, section2, section3] identifierKeyPath:nil];
同时,有许多API用于简化代理和数据源的实现。
// access all items across all sections as a flat array
dataModel.items;
// access items organized by sections
dataModel.sections;
// number of sections
[dataModel numberOfSections];
// number of rows in section
[dataModel numberOfRowsInSection:section];
// look up item at a given index path
[dataModel itemAtIndexPath:indexPath];
// look up index path for a given item
[dataModel indexPathForItem:item];
作为不可变对象,TLIndexPathDataModel
中的所有属性和方法都是只读的。因此,一旦选择合适的初始化器,使用数据模型将非常简单。
TLIndexPathUpdates
TLIndexPathUpdates
是一个伴生类,用于处理对 TLIndexPathDataModel
的批量更新。您向初始化器提供您数据模型的两版,然后计算出插入、删除和移动。然后调用 performBatchUpdatesOnTableView:
或 performBatchUpdatesOnCollectionView:
来执行更新。
// initialize collection view with unordered items
// (assuming view controller has a self.dataModel property)
self.dataModel = [[TLIndexPathDataModel alloc] initWithItems:@[@"B", @"A", @"C"]];
[self.collectionView reloadData];
// ...
// sort items, update data model & perform batch updates (perhaps when a sort button it tapped)
TLIndexPathDataModel *oldDataModel = self.dataModel;
NSArray *sortedItems = [self.dataModel.items sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
self.dataModel = [[TLIndexPathDataModel alloc] initWithItems:sortedItems];
TLIndexPathUpdates *updates = [[TLIndexPathUpdates alloc] initWithOldDataModel:oldDataModel updatedDataModel:self.dataModel];
[updates performBatchUpdatesOnCollectionView:self.collectionView];
这就足够了!
TLIndexPathController
TLIndexPathController
是 TLIndexPathTools 版的 NSFetchedResultsController
。因此,如果您想集成 Core Data,必须使用此类,这并不会让人感到惊讶。
尽管它主要用于 Core Data 集成,但 TLIndexPathController
可以与 NSFetchRequest
或任何数据类型的纯数组交互相用。因此,如果您选择在 TLIndexPathController
上统一视图控制器,就可以在所有表格和集合视图中拥有一个通用的编程模型。
TLIndexPathController
相对 NSFetchedResultsController
做了一些改进。
- 项目不需要在分区中预先排序。数据模型负责组织分区。
- 对检索请求的更改将是动画的。因此,您可以获得动画排序和筛选。
- 只需要实现一个代理方法(相对于
NSFetchedResultsController
的五个方法)。
在(表格)视图中使用 TLIndexPathController
的基本模板如下
#import <UIKit/UIKit.h>
#import "TLIndexPathController.h"
@interface ViewController : UITableViewController <TLIndexPathControllerDelegate>
@end
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) TLIndexPathController *indexPathController;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.indexPathController = [[TLIndexPathController alloc] init];
}
#pragma mark - UITableViewDataSource
- (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"];
id item = [self.indexPathController.dataModel itemAtIndexPath:indexPath];
//configure cell using data item
return cell;
}
#pragma mark - TLIndexPathControllerDelegate
- (void)controller:(TLIndexPathController *)controller didUpdateDataModel:(TLIndexPathUpdates *)updates
{
[updates performBatchUpdatesOnTableView:self.tableView withRowAnimation:UITableViewRowAnimationFade];
}
@end
此模板适用于纯数组或 NSFetchRequests
。对于纯数组,您只需设置控制器(或设置 items
属性并获取默认数据模型)的 dataModel
属性。对于 NSFetchRequests
,您设置 fetchRequest
属性并调用 performFetch:
。从那时起,当检索结果发生变化时,控制器将内部更新数据模型(使用内部实例的 NSFetchedResultsController
并响应 controllerDidChangeContent
消息)。
在这种情况下,无论您是否显式设置了数据模型,还是控制器将检索结果转换为数据模型,控制器都会为您创建 TLIndexPathUpdates
对象并将其传递给代理,这样您就可以执行批量更新。
- (void)controller:(TLIndexPathController *)controller didUpdateDataModel:(TLIndexPathUpdates *)updates
{
[updates performBatchUpdatesOnTableView:self.tableView withRowAnimation:UITableViewRowAnimationFade];
}
《willUpdateDataModel》委托方法是《TLIndexPathController》功能的亮点之一,它为委托提供修改数据模型的机会,在调用《didUpdateDataModel》之前。与Core Data集成时,可以实现一些有趣的应用方式。例如,它可以用来混合非Core Data对象(尝试用《NSFetchedResultsController》来做)。另一个有趣的用途是在数据模型为空时自动显示“没有结果”的消息(在扩展文件夹中提供了《TLNoResultsTableDataModel》类)。
- (TLIndexPathDataModel *)controller:(TLIndexPathController *)controller willUpdateDataModel:(TLIndexPathDataModel *)oldDataModel withDataModel:(TLIndexPathDataModel *)updatedDataModel
{
if (updatedDataModel.items.count == 0) {
return [[TLNoResultsTableDataModel alloc] initWithRows:3 blankCellId:@"BlankCell" noResultsCellId:@"NoResultsCell" noResultsText:@"No results to display"];
}
return nil;
}
TLTableViewController 和 TLCollectionViewController
《TLTableViewController》和《TLCollectionViewController》是使用《TLIndexPathController》并实现基本数据源和委托方法的表格和集合视图基类,以便您可以快速启动和运行。这两个类与上面用于集成《TLIndexPathController》的代码非常相似。
这两个类都支持视图控制器支持的单元格。通过重写《instantiateViewControllerForCell:》方法可以轻松启用此功能。例如,请参阅View Controller Backed示例项目。
《TLTableViewController》还包含一个默认的实现《heightForRowAtIndexPath》方法,使用原型单元格实例计算静态或数据驱动单元格的高度。例如,如果您使用的是Storyboard,Storyboard中指定的单元格高度将自动使用。如果您的单元格实现了《TLDynamicSizeView》协议,高度将由调用原型单元格上的《sizeWithData:》方法来确定。这是处理数据驱动高度的好方法,因为《sizeWithData:》方法可以使用单元格本身的实际布局逻辑,而不是在视图控制器中重复布局逻辑。
大多数示例项目都是基于《TLTableViewController》或《TLCollectionViewController》的,所以快速浏览一下将让您对用几行代码能完成什么有一个很好的想法。
文档
通过运行Docset项目可以生成Xcode套件。构建配置假定在/usr/local/bin/appledoc安装了《Appledoc》。可以在TLIndexPathTools项目| Docset目标|构建阶段标签|运行脚本中更改此设置。
API文档也在线提供。
关于SwiftKick Mobile
我们构建高质量的移动应用!如果您在项目中需要帮助,请联系我们:联系我们。