【问题标题】:UITableView On Screen Image Download Lazy LoadingUITableView 屏幕图像下载延迟加载
【发布时间】:2013-02-23 19:39:35
【问题描述】:

首先这不是重复的。我看到了一些相同的问题,但它们对我没有帮助,因为我的问题略有不同。

使用以下代码,我在我的项目中异步下载图像。

{
    NSURL *imageURL = [NSURL URLWithString:imageURLString];
    [self downloadThumbnails:imageURL];
}

- (void) downloadThumbnails:(NSURL *)finalUrl
{
    dispatch_group_async(((RSSChannel *)self.parentParserDelegate).imageDownloadGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSData *tempData = [NSData dataWithContentsOfURL:finalUrl];

        dispatch_async(dispatch_get_main_queue(), ^{

            thumbnail = [UIImage imageWithData:tempData];
        });
    });
}

由于程序的逻辑,我在 tableview 控制器以外的文件中使用了上面的代码,它在从 web 服务获取数据后显示所有数据。

问题: 屏幕上的图像在我滚动之前不会显示。首先刷新离屏图像。我该怎么做才能解决我的问题。

Apple 的延迟加载项目正在使用 scrollViewDidEndDragging 和 scrollViewDidEndDecelerating 来加载图像,但该项目太大而无法理解,而且我的代码位于 tableview 控制器以外的文件中。

注意:请勿推荐第三方库,如 SDWebImage 等。

更新:由于大多数人无法解决这个问题,我必须澄清这个问题与下载、缓存和重新加载 tableview 中的图像无关。所以请不要推荐第三方库。问题是图像仅在用户滚动表格视图而不是加载屏幕视图时显示。

提前致谢

【问题讨论】:

  • 你应该展示你的数据源代码:你是如何得到图像的?如果确实存在保存图像的任何依赖关系,何时调用数据源方法?在保存/下载图像之前/之后?
  • 它与我之前在上一个问题中发送给您的项目相同。你能好好看看吗?当我使用模型视图控制器存储设计时,它变得非常混乱,其中连接、存储和数据源文件不同但相互依赖。这就是为什么我没有将所有代码都放在问题中
  • 根据您的更新:我相信您的问题在于下载、缓存和重新加载图像。否则,为什么在 cellForRowAtIndexPath 期间不能在单元格中设置它们?

标签: ios objective-c xcode uitableview uiscrollview


【解决方案1】:

我认为你要做的是:

  1. 在下载图像时在表格单元格中显示一些占位符图像(否则您的表格将看起来是空的);

  2. 当下载的图像在那里时,向您的表发送一条刷新消息。

对于 2,您有两种方法:

  1. 简单的一个:将reloadData 发送到您的表格视图(并检查您的应用程序的性能);

  2. 向您的表格视图发送消息:

    - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
    

使用reloadRowsAtIndexPaths 会好很多,但它需要您跟踪哪个图像与哪个表格行相关联。

请记住,如果您使用 Core Data 来存储图像,那么通过将 NSFetchedResultController 与您的表格视图集成,这个工作流程会变得更加容易。 See here for an example.

另一种方法是使用 KVO:

  1. 在 ItemsViewCell 中声明这个观察方法:

    - (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context {
    
    if ([keyPath isEqual:@"thumbnail"]) {
      UIImage* newImage = [change objectForKey:NSKeyValueChangeNewKey];
      if (newImage != (id)[NSNull null]) {
        self.thumbContainer.image = newImage;
        [self.thumbContainer setNeedsLayout];
      }
    }
    
    }
    
  2. 然后,当您配置单元格时:

    RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
    cell.titleLabel.text = [item title];
    cell.thumbContainer.image = [item thumbnail];
    
    [item addObserver:cell forKeyPath:@"thumbnail" options:NSKeyValueObservingOptionNew context:NULL];
    

通过这样做,每当给定的item“缩略图”键路径发生变化时,cell 都会收到通知。

另一个必要的改变是做这样的分配:

       self.thumbnail = [UIImage imageWithData:tempData];

(即,使用self.)。

另一个编辑:

我想像 Apple 的 LazyTableImages 示例一样下载和加载图像。当它不减速和拖动时,则只加载屏幕图像,而不是一次加载所有图像。

我怀疑我们在这里讨论的是不同的问题。

我认为您的问题是下载的图像未正确显示(如果您不滚动表格)。这是我从你的问题中了解到的,我的建议解决了这个问题。

关于延迟加载,您正在执行的操作(下载整个提要,然后将其作为一个整体归档)与您想要的操作(延迟加载)之间存在某种不匹配。这两件事不匹配,所以你应该重新考虑你在做什么。

除此之外,如果您想延迟加载图片,您可以按照以下步骤操作:

  1. parser:foundCDATA:不加载图片,只存储图片URL;

  2. 开始下载tableView:cellForRowAtIndexPath:中的图片(如果你知道URL,你可以使用dataWithContentOfURL,就像你在一个单独的线程上做的那样);

  3. 我上面贴的代码会在图像存在时更新表格;

  4. 一开始不用担心滚动/拖动,只要让 1-2-3 工作即可;

  5. 一旦工作,使用滚动/拖动代理防止图像在滚动/拖动期间被下载(第 2 点);您可以在表格视图中添加一个标志,并让tableView:cellForRowAtIndexPath: 仅在标志显示“禁止滚动/拖动”时下载图像。

我希望这足以让您获得最终结果。我不会为此编写代码,因为它非常琐碎。

PS:如果您延迟加载图像,您的提要将存储在磁盘上而没有图像;您也可以删除 CGD 组和 CGD 等待。正如我所说,没有办法解决这个问题:您不能在进行延迟加载的同时将图像与提要一起存档(除非每次您都获得了一个新图像,您将整个提要存档) .你应该找到另一种缓存图像的方法。

【讨论】:

  • 我之前尝试过类似的方法。但它太基础了。这个实现首先加载顶部的,然后一直向下加载,而不是像 Apple 的lazytableImages 示例那样在用户向下滚动时立即加载。我怎样才能产生这种效果?
  • plus 看起来每次调用 reload data 都会有性能损失
  • 我希望我不会打扰你,但这是做同样事情的另一种方式。我想像 Apple 的 LazyTableImages 示例一样下载和加载图像。当它不减速和拖动时,只加载屏幕上的图像,而不是一次加载所有图像。我能以更简单的方式在我的项目中使用该功能吗?
  • 我希望我加载和缓存的方式不会降低性能。我已将其作为正确答案进行了检查,因为它修复了我项目中的刷新问题。您提到的延迟加载的其余要点,我稍后会在我的项目中重新审视它们以实现它。再次非常感谢您解决问题。非常感谢。
  • 您可能会遇到一些内存限制,因为所有图像都是一次下载的(并一直保存在内存中,直到最终存档);另一方面,使用 KVO 的表实现非常高效;检查 Instruments 以查看下载提要时内存是否增长很多。
【解决方案2】:

尝试使用SDWebImage,它非常适合在 UITableViews 中使用来自网络的图像并为您处理大部分工作。

【讨论】:

  • 嗯,我已经完成了图片的异步下载,并保存了数据并重新加载。你确定 SDWebImage 库也处理屏幕上的图片加载吗??
  • 它在屏幕上加载图像方面做得很好。无需滚动即可加载它们,它们只是加载。节省一些时间并尝试一下。
  • 我已经自己加载、缓存等。我问的问题不同。
  • 为什么要重新发明轮子?除非您在推出自己的产品时做一些非常独特的事情,否则最好使用许多人使用的开源解决方案。完成下载并设置好图片后,您是否尝试过在 UIImageView 上调用setNeedsLayout
【解决方案3】:

最好的办法是缓存图像并使用它们。我已经编写了表格视图的代码。 Image on top of Cell 这是一个很好的解决方案。

【讨论】:

  • 我已经完成了下载、持久化和重新加载。所以我不需要为此目的的库。问题不同。
  • 我会建议你每次都重新加载你的表。表格的滚动视图每次都会重新加载您的表格。但我会推荐你​​到上面的链接。它会自动缓存并在滚动时加载图像。这些是简单的类而不是一个大图书馆。尝试一次,你会很开心。
【解决方案4】:

尝试使用此代码下载图片,

 - (void) downloadThumbnails:(NSURL *)finalUrl
  {
     NSURLRequest* request = [NSURLRequest requestWithURL:finalUrl];
    [NSURLConnection sendAsynchronousRequest:request 
                     queue:[NSOperationQueue mainQueue]
                     completionHandler:^(NSURLResponse * response,
                     NSData * data, NSError * error)
                    {
                      if (!error)
                       {
                      thumbnail = [UIImage imageWithData:data];

                       }       

   }];
 }

【讨论】:

  • 下载、缓存、加载等已经完成。我的问题是关于首先显示顶部图像并在用户向下滚动时加载
猜你喜欢
  • 2010-11-10
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-23
  • 1970-01-01
  • 2013-10-24
  • 2021-08-15
相关资源
最近更新 更多