测试已测试 | ✗ |
语言语言 | Objective-CObjective C |
许可证 | MIT |
发布上次发布 | 2014年12月 |
由 Jason Barrie Morley 维护。
确定 UITableView
和 UICollectionView
正确的更新集是困难的。 ISListViewAdapter
会为您完成所有这些工作,将标识符数组映射到列表视图所需的内部结构。当标识符数组发生变化时,它可以自动确定增加、删除、更新和移动操作,并且可以使用提供的各种便利方法将这些操作应用到 UITableView
和 UICollectionView
上。
ISListViewAdapter
需要客户端实现数据源和绑定到 UITableView
或 UICollectionView
实例的粘合剂。
客户端必须提供 ISListViewAdapterDataSource
协议的自定义实现,该协议作为 ISListViewAdapter
的数据模型。 ISListViewAdapterDataSource
通过不透明的标识符索引条目,而 ISListViewAdapter
保持在 UITableView
和 UICollectionView
使用和这些标识符之间的映射。
这个协议的简单实现示例可能会如下所示。这仅仅是将内容暴露在 NSDictionary
上。
#import <ISListViewAdapter/ISListViewAdapter.h>
#import "CustomDataSource.h"
@interface CustomDataSource ()
@property (nonatomic, strong) NSDictionary *items;
@property (nonatomic, strong) ISListViewAdapterInvalidator *invalidator;
@end
@implementation CustomDataSource
- (id)init
{
self = [super init];
if (self) {
self.items =
@{@"item_a": @{@"title": @"Title For Item A",
@"section": @"Section One"},
@"item_b": @{@"title": @"Title For Item B",
@"section": @"Section Two"},
@"item_c": @{@"title": @"Title For Item C",
@"section": @"Section One"}};
}
return self;
}
// Required
- (void)identifiersForAdapter:(ISListViewAdapter *)adapter completionBlock:(ISListViewAdapterBlock)completionBlock
{
completionBlock([self.items allKeys]);
}
- (void)adapter:(ISListViewAdapter *)adapter itemForIdentifier:(id)identifier completionBlock:(ISListViewAdapterBlock)completionBlock
{
NSDictionary *item = self.items[identifier];
completionBlock(item);
}
// Optional
- (id)adapter:(ISListViewAdapter *)adapter summaryForIdentifier:(id)identifier
{
NSDictionary *item = self.items[identifier];
return [NSString stringWithFormat:
@"%@, %@",
item[@"title"],
item[@"section"]];
}
- (NSString *)adapter:(ISListViewAdapter *)adapter sectionForIdentifier:(id)identifier
{
NSDictionary *item = self.items[identifier];
reeturn item[@"section"];
}
// Called when the data source is added to the adapter.
// ISListViewAdapterInvalidator should be retained if it is ever necessary for
// the data source to invalidate the ISListViewAdapter.
- (void)adapter:(ISListViewAdapter *)adapter initialize:(ISListViewAdapterInvalidator *)invalidator
{
self.invalidator = invalidator;
}
@end
所有数据源回调都在主运行循环上执行。可以使用完成块异步提供长运行操作的结果。请注意,由于所有回调都在主运行循环上执行,您应将任何长时间运行的操作跨帖子以避免阻塞 UI。
摘要和章节回调是可选的
adapter:summaryForIdentifier:
返回一个符合 NSObject
的 id
(用于通过 isEqual:
比较),它描述了给定标识符的项目当前状态。它被 ISListViewAdapter
用于识别项目的更新。如果没有提供摘要,则假定对象不可变,项目将不会被更新或重新加载。adapter:sectionForIdentifier:
返回要显示给定标识符的项目所属章节的标题(假定是唯一的)。章节内的项目排序对应于通过 identifiersForAdapter:completionBlock:
返回的排序。章节排序对应于通过 identifiersForAdapter:completionBlock:
返回的项目的查看顺序。一旦有了数据源,就必须创建一个 ISListViewAdapter
实例,并将其绑定到您的列表视图实例。 ISListViewAdapterConnector
为 ISListViewAdapter
实例与表格视图和收集视图提供了一种现成的连接器。
#import <ISListViewAdapter/ISListViewAdapter.h>
#import "CustomTableViewController.h"
#import "CustomDataSource.h"
@interface CustomTableViewController ()
@property (nonatomic, strong) id<ISListViewAdapterDataSource> dataSource;
@property (nonatomic, strong) ISListViewAdapter *adapter;
@property (nonatomic, strong) ISListViewAdapterConnector *connector;
@end
@implementation CustomTableViewController
- (void)viewDidLoad
{
self.dataSource = [CustomDataSource new]
self.adapter = [ISListViewAdapter adapterWithDataSource:dataSource];
self.connector = [ISListViewAdapterConnector connectorWithAdapter:adapter
tableView:self.tableView];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Inform the connector that our view has been fully constructed and it is safe to
// apply incremental updates to our UITableView (or UICollectionView).
[self.connector ready];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.connector numberOfSections];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.connector numberOfItemsInSection:section];
}
- (NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section
{
return [self.adapter titleForSection:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell =
[self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier
forIndexPath:indexPath];
NSDictionary *item = (NSDictionary *)[[self.adapter itemForIndexPath:indexPath] fetchBlocking];
// Configure the cell using the details of the fetched item. e.g.
cell.textLabel.text = item[@"title"];
return cell;
}
@end
如果您希望使用自己实现的列表视图与 ISListViewAdapter
结合,或者以自定义的方式处理更改(例如,将更改的项目滚动到视图),则可以实现 ISListViewAdapterObserver
协议,并使用 addAdapterObserver:
和 removeAdapterObserver:
来观察 ISListViewAdapter
。
- (void)adapter:(ISListViewAdapter *)adapter performBatchUpdates:(ISListViewAdapterChanges *)changes
{
for (ISListViewAdapterOperation *operation in changes.operations) {
// Check the type of the operation and determine the correct change...
}
}
ISListViewAdapterItem
为根据 NSIndexPath
获取项目提供了一个机制。项目自身为 id
类型,允许您在内部使用任何对象:上面的例子使用了 NSDictionary
实例作为项目,但这也可以是您自己的自定义对象(如 NSManagedObject
、FCModel
等)。
项目可以同步和异步获取。通常,同步获取项目是安全的(如果您使用的是快速机制,如 NSDictionary
进行项目查找),但如果您正在从数据库或其他较慢的数据源中进行获取,则可能希望使用异步获取。在极端情况下,异步获取可能用于直接从网络获取项目。
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = /* ... */
ISListViewAdapterItem *item = [self.adapter itemForIndexPath:indexPath];
id myItem = [item fetchBlocking];
// Configure the cell...
return cell;
}
ISListViewAdapterItem fetch:
保证无论支持数据源的行为如何,回调都会在主运行循环中发生。
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = // ...
__weak UITableViewCell *weakCell = cell;
ISListViewAdapterItem *item = [self.adapter itemForIndexPath:indexPath];
[item fetch:^(id myItem) {
UITableViewCell *strongCell = weakCell;
if (cell) {
// Configure the cell...
// Ensure the cell is redrawn.
[cell setNeedsLayout];
}
}];
return cell;
}
有时,在数据源之间进行转换很有用。
CustomDataSource *secondDataSource = [CustomDataSource new];
[self.adapter transitionToDataSource:secondDataSource];
ISListViewAdapter
为非常大的数据集而设计。
ISListViewAdapter
都会创建自己的 dispatch queue:在大数据集中,更新可能需要更长时间计算,但这样做不应该阻止主运行循环。ISListViewAdapter 包含一些相当全面的浸泡测试,旨在用尽可能多的输入来驱动 UITableView 和 UICollectionView。
cd Sample
pod install
xcodebuild build -workspace ISListViewAdapterSample.xcworkspace -scheme ISListViewAdapterSample
ISListViewAdapter
通过首先识别和应应用到部分插入、删除和移动,然后在应用部分更改之后,仅确定项目更改来识别更改。这意味着,在当前实现中,项目永远不会在部分之间进行动画过渡。
ISListViewAdapter 在 MIT 许可证下可用。有关更多信息,请参阅 LICENSE 文件。