Background
iPhone屏幕的刷新频率固定为60fps,为了达到流畅的滑动效果,iOS应用展示必须满足该条件。当帧率很低时,就会出现明显的卡顿现象。
60fps相当于每帧16.67毫秒,在这么短的时间内collection view可能并不能完成从相对较慢的数据源加载数据。为了提升collection view性能,一个常用的技巧是使cellForItemAtIndexPath
尽可能快的返回cell,比如异步加载网络图片等。为了进一步提高collection view性能,并且尽量减少开发者的工作,在iOS 10中引入了新特性。
UICollectionView API变化
新增UICollectionViewDataSourcePrefetching协议
1 2 3 4 5 6 7 8 9 10 11 |
|
这两个方法均异步执行,可用于异步加载图片等。
新增prefetchDataSource代理
1
|
|
新增prefetchingEnabled属性
1
|
|
Prefetching
当collection view滑动速率将要超过cellForItemAtIndexPath
返回cell的速率时,collection view会调用prefetchItemAtIndexPaths:
方法。
collection view会把可能即将需要展示的cell的IndexPath放入数组中传递给prefetch方法。这为我们提供了预处理数据机会。比如,当我们需要加载网络图片时,可以在prefetch方法中请求网络数据,并把下载的数据插入到data source中,为cellForItemAtIndexPath
的使用做准备。
当collection view滑动方向改变时,collection view会调用cancelPrefetchingForItemsAtIndexPaths
方法。
该方法的目的是取消原本可能即将展示的cell的预加载数据工作。参数同样是IndexPath的数组。
UICollectionView Cell生命周期变化
UICollectionViewCell Lifecycle: iOS <= 9
- 首先,调用
cellForItemAtIndexPath:
,从复用队列中弹出一个cell,准备对其调用prepareForReuse
。 - 然后,根据需求设置cell的内容,比如labels等。
- 当cell即将出现时,调用
collectionView:willDisplayCell:forItemAtindexPath:
。 - 当cell消失时,调用
collectionView:didEndDisplayingCell:forItemAtIndexPath:
。此时cell会重新进入复用队列,等待复用。 - 当用户向相反方向再次把cell滑回屏幕时,会重新从第一步开始执行。
UICollectionViewCell Lifecycle: iOS 10
在iOS 10中,前3个步骤与iOS 9是相同的,新的变化发生在cell滑出屏幕的时候。
当调用collectionView:didEndDisplayingCell:forItemAtIndexPath:
后,cell不会立刻进入复用队列,系统会keeps it around for a bit。相当于会缓存该cell一小段时间,在这段时间内如果该cell再次回到屏幕中,便不会重新调用cellForItemAtIndexPath:
,而是直接显示。
至于系统会缓存多久,官方并没有给出明确的时间,感觉跟程序运行时开销有关。
如果想关闭该功能,需要设置collectionView.prefetchingEnabled = NO;
。
collection view包含多列的情况,主要体现cell的独立性。
当某一行需要展示时,每个cell独立出队并调用cellForItemAtIndexPath:
方法;
当该行即将展示时,每个cell调用willDisplayCell:atIndexPath:
。
总结
- 这些变化对开发者都是透明的,对开发者来说只需利用好prefetch特性。
- prefetch进一步提升了collection view的性能,尤其是获取cell数据开销比较大或者比较慢时。
- 每个cell独立出队,单独设置,确保cell在展示之前总是ready。
- UITableView拥有相同的新特性。