iOS 10 —使用预提取API滚动UICollectionViewDataSourcePrefetching

以下讨论的所有内容均来自此WWDC视频 。 这个长达35分钟的视频包含有关UICollectionView增强功能的所有详细信息,并解释了为什么添加此Pre-Fetch API,现有的滚动体验,帧掉落等问题是什么?

所以现在,让我们进入理论,

随着开发的任何移动应用程序用户规模的增长,该应用程序能够承受各种网络呼叫,各种设备和屏幕尺寸变得越来越重要。 理想情况下,每个应用程序都需要交付即时的内容交付,不丢帧(或不浪费网络数据)。 为了实现这一目标,我想通过“后台预取”(已经通过在各种应用程序中使用不同的机制来解决这一问题!)是打破所有其他依赖关系并平稳运行/滚动的方式。 用“ Background pre-fetching”(背景预先提取)一词,这是不言而喻的,任何移动应用程序都应该在后台提取足够的数据,并准备好将它们预先显示在屏幕上,从而可以流畅地观看内容。

在分析任何应用程序时,滚动时通常会由于以下原因而导致内容下降或滞后:

1.网络可用性

网络连接将会频繁下降,因此移动应用必须提出一种不同的实时获取内容的策略。 如果我们以相同的次数定位许多用户,则移动应用程序必须处理网络带宽速度。

2.切换连接类型

移动应用必须观察其用户sim或wifi或两者之间的切换的不同使用模式。 根据用户已在其移动应用程序中连接的连接,内容将显示得更快或更慢。

3.没有互联网连接

如果移动应用程序完全失去了互联网连接怎么办? 是否向用户显示提示说没有互联网连接(或),一个带有加载/刷新图标的占位符单元足够,以便在互联网连接重新打开时重新加载,是否很好?

从任何移动角度来看,它将是以下两个选项之一:

1. 脱机数据处理 ,以从应用程序的数据库中获取并显示先前获取的内容。
2. 缓存机制 ,我们在其中缓存内容并显示它们。

现在,如果没有先决条件,所有条件都得到满足,但移动应用程序仍然没有流畅的滚动体验,该怎么办?

在iOS 10上,Apple引入了“ 数据预取 ”概念及其相关的API后,在UICollectionViewUITableView中都可以在后台线程中预取数据以体验流畅的滚动体验,它确实有效! 操作系统负责在后台获取其他数据。

在直接进入API方法之前,让我们看一下iOS 9中UICollectionView的生命周期:

1. collectionView(_:cellForItemAt 🙂 -单元格将进入带有内容的可见区域。
2. collectionView(_:willDisplay:forItemAt 🙂 -单元格进入带有内容的可见区域。
3. collectionView(didEndDisplaying:forItemAt 🙂 -单元格在可见字段之外。

现在,iOS 10中的UICollectionView的生命周期:

它与iOS 9相似,但是按照Apple的解释,操作系统更早地调用collectionView(_:cellForItemAt 🙂 ,这意味着,即使在需要显示单元格之前,也可以完成所有繁重的工作。 另一个是,使用iOS 10时,会调用collectionView(didEndDisplaying:forItemAt 🙂 ,但不会立即回收该单元格。 进行反向滚动时,无需重新加载内容。 在iOS 10中,即将进入可见区域的每个单元格都会单独加载。

我们可以看到多列布局的区别。 通过预取来实现平滑度。 为了利用预取,必须在collectionView(_:cellForItemAt :)中执行cell的庞大配置。
collectionView(_:willDisplay:forItemAt 🙂collectionView(didEndDisplaying:forItemAt 🙂应该保持最小。

预提取API自iOS 10附带,因此要关闭此API,请将UICollectionView的isPrefetchingEnabled属性设置为false(如果不需要)。

UICollectionViewDataSourcePrefetching协议是iOS 10公开的API。它有两种方法,

1. collectionView(_:prefetchItemsAt:) (必填)—此方法允许启动单元格所需数据的异步加载。 此方法将数据加载的负担从主队列转移到后台队列。

2. collectionView(_:cancelPrefetchingForItemsAt:) (可选)—此方法使我们可以根据需要取消挂起的数据加载,这是通过取消不必要的工作来节省CPU时间的好方法。

好的部分是自适应的,这意味着上述方法是根据用户与应用程序交互的方式触发的。 collectionView(_:prefetchItemsAt :)的一个缺点是可能不会为每个CollectionView单元调用此方法,因此应用程序应该能够处理已经获取,正在获取但尚未请求的数据。

对于UITableview,其tableView(_:prefetchRowsAt 🙂tableView(_:cancelPrefetchingForRowsAt 🙂

要执行预取数据的5个步骤,必须在Apple开发人员站点上提供一个示例使我们更好地理解。

第1步-启用预取

class YourCustomDataSource: NSObject, UICollectionViewDataSource, UICollectionViewDataSourcePrefetching { 
 } 

第2步-分配prefetchDataSource属性

 最后的类ViewController:UIViewController { 
// MARK:属性
  IBOutlet var collectionView:UICollectionView! 
 私人let dataSource = YourCustomDataSource() 
  /// —标签:SetDataSources 
覆盖func viewDidLoad(){
super.viewDidLoad()
  //设置集合视图的数据源。 
collectionView.dataSource =数据源

//设置集合视图的预取数据源。
collectionView.prefetchDataSource =数据源
}

第3步-异步加载数据

当加载数据是一个缓慢或昂贵的过程时,可以使用数据预取。

  func collectionView(_ collectionView:UICollectionView,prefetchItemsAt indexPaths:[IndexPath]){ 
//开始异步获取请求的索引路径的数据。
用于indexPaths中的indexPath {
让模型= yourmodels [indexPath.row]
yourfetchClass.fetch(model.id)
}
}

步骤4 —填充要显示的单元格

  func collectionView(_ collectionView:UICollectionView,cellForItemAt indexPath:IndexPath)-> UICollectionViewCell { 
守卫让细胞= collectionView.dequeueReusableCell(withReuseIdentifier:Cell.reuseIdentifier,for:indexPath)为? 单元格其他{
fatalError(“预期\(Cell.self)”)
}
//这里是您已经在执行的常规cellForItemAtIndexPath获取机制。
 返回单元 
}

步骤5 —取消不必要的提取

  func collectionView(_ collectionView:UICollectionView,cancelPrefetchingForItemsAt indexPaths:[IndexPath]){ 
//取消对指定索引路径的任何数据请求。
用于indexPaths中的indexPath {
让模型=模型[indexPath.row]
yourfetchClass.cancelFetch(model.id)
}
}

示例代码和解释在这里 从苹果。 另外,您可以在Apple网站上搜索以获取详细说明。

最后总结一下,如果我们使用这些最近添加的API,则可以充分利用所有新的操作系统优化功能,并在与我们的移动应用程序进行交互时提供最佳的用户体验。