问题 带有infite滚动和延迟加载的UITableView


我有一个 UITableView 它充满了未知数量的行。每行包含(例如3个)图像,应用程序从Web服务收集此信息。

为了 UITableView 我实现了无限滚动。每当表几乎达到当前行数的末尾时,我就会启动对webservice的调用,以获取接下来的50行数据。我这样做了 scrollViewDidScroll 由...调用的方法 UITableView

- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat actualPosition = scrollView.contentOffset.y;

    float bottomOffset = 450;
    if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
        bottomOffset = 1000;

    CGFloat contentHeight = scrollView.contentSize.height - bottomOffset;
    if (actualPosition >= contentHeight && !_loading && !_cantLoadMore)
    {
        self.loading = YES;

        _currentPage++;

        NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
        [dict setObject:[NSNumber numberWithInt:_currentPage] forKey:@"page"];
        [dict setObject:[_category objectForKey:@"ID"] forKey:@"category"];

        [self performSelectorInBackground:@selector(getWallpapersInBackground:) withObject:dict];
    }
}

行中的图像 UITableView 很懒。每当一行可见时,图像将被加载到一个单独的线程中,并且一旦完全下载图像就会更新行。我用于延迟加载的原则与Apple在其文档中建议的相同。图像也会添加到本地 NSDictionary,所以当行滚出屏幕然后重新进入(并重新创建行)时,我可以获取它。

因为单个视图中的图片数量可以达到2000 - 3000,我还会将图像缓存到磁盘并清除图像中的图像。 NSDictionary 当它们超过X行时。当用户向下和向上滚动时,会发生以下情况:

  1. 显示新行
  2. 调用延迟加载方法,该方法检查图像是否存在于磁盘上或者应该下载它。
  3. 从磁盘下载或获取映像时,它会执行代码块,该代码块在行中显示图像。从Internet下载的图像也会缓存到磁盘。
  4. UIImage 被添加到 NSDictionary 用于更快地缓存需要触及的图像。
  5. 从可见行中排成行,15行或更远的图像将被删除 NSDictionary,因为记忆问题(太多了 UIImage 中的对象 NSDictionary 导致内存不足错误)。

当UITableView几乎到达结尾时,会发生以下情况:

  1. UITableView几乎到达当前加载的行的末尾
  2. 调用webservice,加载新行(50)
  3. 新行被添加到一个数组,用于 numberOfItemsInSection 方法。
  4. 一个 reloadData 被称为确保 UITableView 填充额外的新行。
  5. 包含图像的新行执行上述步骤以延迟加载图像。

所以,我遇到的问题是当我从webservice添加新记录时。当我打电话给 reloadData 在...上 UITableView 一些图像再次从磁盘加载,并在滚动时发生一些hickup。

我正在为此寻找解决方案。我试过用 insertItemsAtIndexPaths 用新行的数量,将它们添加到 UITableView,但这使得我的延迟加载方法已经下载了图像(因为不知何时所有单元格都是在那时创建的,即使它们不可见,检查单元格在创建期间是否可见会产生意外结果,图像无法加载,单元格看起来很奇怪,等等)。

因此,我基本上寻找的是无限滚动UITableView的解决方案,它延迟加载来自Web /磁盘的图像,并且与照片应用程序一样流畅。由于图像都是在不同的线程中加载的,我不明白为什么滚动不像婴儿的皮肤那么光滑。


9909
2018-06-30 11:39


起源

KTPhotoBrowser 是一个非常好的图片库,用于照片浏览,下载和缓存。您可以修改它以满足您的需求。 - Hejazi


答案:


我不确定我是否完全了解你的问题,但是在遇到类似的问题时我会做一些事情。

  • 我用了 -tableView:cellForRowAtIndexPath: 作为我从网上加载更多数据的提示。我选了一个号码(在我的情况下是10) indexPath.row + 10 >= self.data.count 加载更多数据。

    • 我需要打电话 -tableView:cellForRowAtIndexPath: 无论如何。
    • 我没有强制回调到更严格的循环 -scrollViewDidScroll:
  • 我继承了 UIImageView 用一个异步加载我调用的图像的类 URLImageView

    • -tableView:cellForRowAtIndexPath:,我分配了一个URL URLImageView 实例。
    • 该分配导致后台操作从磁盘加载或从Web加载。
    • 该操作是可取消的,因此我没有继续处理不再需要加载的图像。

我有一张包含数百张(但不是数千张)图像的桌面视图。我一次只在屏幕上有2或3个表格单元格。

  • 我用了 -refreshData:它像冠军一样工作。
  • 我甚至得到了 URLImageView 淡化图像。这是一个非常好的效果。

我希望有所帮助。


14
2018-06-30 23:58



你能详细说明吗......我面临同样的问题.. - Rakesh
我不确定你想要详述什么?在 -tableView:cellForRowAtIndexPath:, if (indexPath.row + 10 >= self.data.count) { [self.data loadNextChunkWithCompletion:^{ [tableView reloadData]; }]; },哪里 self.data 是一个数据模型,具有部分加载的数据和 -loadNextChunkWithCompletion: 是一种加载下一部分数据的方法。 - Jeffery Thomas


避免闪烁试试 beginUpdates在桌子上,然后 insertrowAtIndexPaths:withRowAnimations: 并完成 endUpdates

祝你好运。


2
2018-04-05 11:36