【问题标题】:UITableView with infite scrolling and lazy loading具有无限滚动和延迟加载的 UITableView
【发布时间】:2012-06-30 11:39:10
【问题描述】:

我得到了一个UITableView,其中填充了未知数量的行。每行包含(例如 3 张)图像,应用程序从 Web 服务收集这些信息。

对于UITableView,我实现了无限滚动。每当表几乎达到当前行数的末尾时,我都会调用 Web 服务,以获取接下来的 50 行数据。我在 UITableView 调用的 scrollViewDidScroll 方法中执行此操作。

- (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,因此我还将图像缓存到磁盘并在图像超过 X 行时从NSDictionary 中清除图像。当用户再次向下和向上滚动时,会发生以下情况:

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

当 UITableView 快走到尽头时,会出现以下情况:

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

所以,我遇到的问题是当我从 web 服务添加新记录时。当我在UITableView 上调用reloadData 时,一些图像会再次从磁盘加载,并且在滚动时会出现一些问题。

我正在为此寻找解决方案。我尝试将insertItemsAtIndexPaths 与新行的数量一起使用,将它们添加到UITableView,但这使得我的延迟加载方法已经下载了图像(因为当时以某种方式创建了所有单元格,即使它们不是可见,在创建过程中检查单元格是否可见会产生意想不到的结果、图像未加载、单元格看起来很奇怪等)。

所以,我本质上是在寻找一种无限滚动 UITableView 的解决方案,它可以从网络/磁盘延迟加载图像,并且与照片应用程序一样流畅。由于图像都是在单独的线程中加载的,我不明白为什么滚动不像婴儿的皮肤那么光滑。

【问题讨论】:

  • KTPhotoBrowser 是一个非常好的照片浏览、下载和缓存库。您可以对其进行修改以满足您的需要。

标签: iphone ios cocoa-touch


【解决方案1】:

我不确定我是否完全理解你的问题,但这里有一些我在遇到类似问题时所做的事情。

  • 我使用-tableView:cellForRowAtIndexPath: 作为提示从网络加载更多数据。当indexPath.row + 10 >= self.data.count 加载更多数据时,我选择了一个数字(在我的情况下为 10)。

    • 无论如何我都需要打电话给-tableView:cellForRowAtIndexPath:
    • 我没有强制回调到-scrollViewDidScroll: 的更紧密循环中。
  • 我将UIImageView 子类化为一个可以异步加载图像的类,我称之为URLImageView

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

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

  • 我使用了-refreshData:它的效果非常好。
  • 我什至让URLImageView 淡入图像。这是一个非常好的效果。

希望对你有帮助。

【讨论】:

  • 我不确定您想要详细说明什么?在-tableView:cellForRowAtIndexPath:if (indexPath.row + 10 >= self.data.count) { [self.data loadNextChunkWithCompletion:^{ [tableView reloadData]; }]; },其中self.data是一个数据模型,它有部分加载的数据,-loadNextChunkWithCompletion:是一个加载下一部分数据的方法。
【解决方案2】:

为避免闪烁,请尝试在桌子上调用beginUpdates,然后insertrowAtIndexPaths:withRowAnimations: 并以endUpdates 结束。

祝你好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 2017-09-12
    相关资源
    最近更新 更多