一个单例类,它促进了在更新 UITableView、UICollectionView 和其他基于 UIView 的类上的排队操作。
这是一个关于如何异步更新视图的《UITableView/UICollectionView》开源库教程。
UITableView(以及 UICollectionView)期望你在绘制视图之前准备所有数据以填充单元格。在这种情况下,当你在插入、删除、-batchUpdate…
或 -reloadData
时,你的数据源状态与视图状态同步。一切都很完美。
但不幸的是,我们并不总是在绘制视图之前拥有数据。有时我们希望从最少的数据量开始,然后逐步下载更多数据,使应用程序看起来快速且可供使用。因此,你异步地更新 UITableView。但是,当 UITableView 在短时间内重复更新时,这在异步更新中通常会发生,你可能会错过数据源与 UITableView 状态之间的同步。这通常会由于 NSInternalInconsistencyException
或 endupdates EXC_BAD_ACCESS
错误而导致崩溃。《BDUIViewUpdateQueue》帮你排队这些更新,以避免这些问题。
BDUIViewUpdateQueue
使用 Grand Central Dispatch(dispatch_queue_t
)将视图锁定到串行队列,然后在主队列中执行您的块。这样数据源将始终与您的 UITableView 或 UICollectionView 状态同步。其他视图也将这样做。
BDUIViewUpdateQueue
提供了几种锁和更新的变体
-updateView:block:
将输入块添加到与输入视图关联的序列队列中,然后在主队列中顺序执行这些块-updateView:block:delay:
在将输入块添加到与输入视图关联的序列队列中之前延迟输入时间间隔,然后在主队列中顺序执行这些块updateView:block:waitUntil:
将输入块添加到与输入视图关联的序列队列中,定期执行 waitUntil
块直到返回 true,然后在主队列中执行相应的块BDUIViewUpdateQueue
是一个单例类。因此,使用 +shared
获取实例。
[BDUIViewUpdateQueue shared];
BDUIViewUpdateQueue
需要一个 UIView
作为输入来与之关联一个序列队列。这意味着我们可以使用 BDUIViewUpdateQueue
为任意多的 UIView
排队更新。BDUIViewUpdateQueue
会为您跟踪 dispatch_queue_t
结构体。
在输入块内部,您需要在这里更新您的数据源和视图。例如…
[[BDUIViewUpdateQueue shared] updateView:self.tableView block:^{
self.items = @[@"Hello"];
[self.tableView insertIndexPaths@[[NSIndexPath indexPathWithRow:0 section:0 withRowAnimation:UITableViewRowAnimationBottom]];
}];
NSIndexPath
更新存在风险。更新类似于上面示例的UITableView
的常见模式实际上是一个陷阱,尤其是当您的数据源项可以被其他线程重新排列或完全更改时。因此,在视图更新之前通过某种方式重新查找相应的NSIndexPath
会更安全。例如Person *john = [_items objectAtIndex:indexPath.row];
[[BDUIViewUpdateQueue shared] updateView:self.tableView block:^{
//do some work
//[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:0]; //Using an indexPath from outside this block is risky. let's not do this.
//do this instead.
NSUInteger indexToUpdate = [_items indexOfObject:john];
if (indexToUpdate != NSNotFound){
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:indexToUpdate section:0]] withRowAnimation:0];
}
}];
UICollectionView
,即使您将更新排队,如果调用insert/delete/update项的速度超过其限制(31个动画),它也会抛出endAnimation
异常。这个示例可能需要一些解释
如上视频所示,该示例应用程序是使用UITableView
显示数据行的典型例子。首先,行加载了一些占位文本。然后异步下载缩略图。更多JSON信息也异步下载。结果被填充回每个行中,并且该行通过UITableView
重新加载。
在NSLog输出中,您将看到行是如何异步更新的。如果您取消注释所有对BDUIViewUpdateQueue的调用并重新运行应用程序,您将看到该应用程序在没有适当同步的情况下如何工作,这并不美观。
要运行示例项目,请先从示例目录中克隆存储库,然后先从示例目录运行pod install
。
Norsez Orankijanan,http://about.me/norsez
BDUIViewUpdateQueue受MIT许可证的许可。有关更多信息,请参阅LICENSE文件。