预加载UITableView单元格

时间:2012-09-22 09:00:22

标签: ios uitableview

我有一个UITableView,它从数据库中检索一些预取相对昂贵的数据。为了解决这个问题,我使用了LazyTableImages示例代码中的设计思想,在使用[UITableView visibleCells]滚动结束时获取可见行的数据。

这在性能方面效果很好,但它有两个我想解决的交互问题:

  1. 在滚动完全停止(即scrollViewDidEndDecelerating)之前,不会加载数据。因此,如果我在列表中缓慢滚动,我必须停止滚动以将数据加载到那些可见单元格中。理想情况下,如果滚动速度很慢,我会将数据加载到单元格中。
  2. 我想预取一些或两个表格单元格数据,这些数据只是在屏幕上,以期滚动到它们。
  3. 有没有一种优雅的方法来实现这一目标? 我觉得我可能会错过这个问题的常见设计模式。

5 个答案:

答案 0 :(得分:6)

我认为您可以在滚动开始时开始加载数据,这样您就不必等待滚动结束。您可以使用以下两种方法之一:

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{}

此外,您始终可以获取可见单元格的索引,因此我认为您应该能够加载更多数据而不仅仅是可见单元格。

答案 1 :(得分:2)

如果你按原样使用LazyTableImages代码,这是正常的。 延迟加载直到滚动结束。 在我的测试应用程序(一个简单的类似于Instagram的流)中,我使用了一种不同的方法:基本上我将单元格子类化,从单元格本身开始下载,使用单元格作为我的下载管理器的委托,然后更新单元格的UI下载完成后

详细

  • 我在cellForRowAtIndexPath方法中开始下载(如果视图滚动,则LazyTableImages推迟下载,我不会因为对我来说可以在滚动时加载)调用我的单元格的“startDownload”方法。
  • 我的单元子类被设置为我的下载管理器的委托,当下载完成时,单元格会使用真实图像更改占位符(这是在自定义“downloadManagerDidFinishDownloadForImage:(UIImage *)image”委托方法中完成的,在单元子类中实现)
  • 在我的单元子类中,我重写了prepareForReuse方法。在这里,如果要重复使用单元格,我可以选择停止下载。在我的情况下,我只是取消设置委托并继续下载,因为我有一些使用核心数据进行的图像缓存,我希望缓存继续。

此外,你必须要处理两件事:

  • 您的下载管理员需要在后台线程中工作
  • 请务必更新主线程中的单元格UI。您可以使用

dispatch_async(dispatch_get_main_queue(), ^{
    //update here your cell UI
});

在委托方法中(如果下载管理器调用该方法,则确实在后台线程中调用,因此您必须在主线程中“使用调度”“移动”。

如果你想要你可以查看我的例子,但它是“按原样”(它是一个测试应用程序,并且有很多意大利面条代码和与你的问题无关的东西; - )

http://www.lombax.it/documents/InstaXplore.zip

在我的例子中,你必须看看:

  • BrowseCell< - 细胞亚类
  • BrowsePhotoViewController< - tableviewcontroller

其他事情与核心数据存储和Instagram有关,但基本上是

    在cellForRowAtIndexPath中的
  • 我创建一个新单元格(或重用前一个单元格)并传递一个InstaImage项目(我的自定义图像)
  • InstaImage检查是否存在缓存副本,如果不存在,请开始下载,然后提醒单元格

你有一个清晰的缓存按钮可以反复尝试: - )

答案 2 :(得分:1)

// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;



(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
        //fetch data for visible rows
    }
}

答案 3 :(得分:1)

如果我没有误解你的问题,我想你可以用它。您在显示 SOME 单元格时加载。

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

}

答案 4 :(得分:1)

懒惰图像逻辑是一个很好的解决方案,我曾经在我的tableviews中使用,但最近我一直在为UITableViews实现不同的解决方案。第一个是实施NSOperation队列,就像Apple在WWWDC中提供的视频中那样https://developer.apple.com/videos/wwdc/2012/?include=211#211

或者您可以尝试创建无限滚动,当您到达某个uitableviewcell时,您将加载包含更多数据的新“页面”,如果您需要此解决方案的帮助,请告诉我们!

希望这有帮助!

最好的问候,

豪尔赫。