在UITableView中延迟加载多个图像

下载多个图像并在UITmageView内部的UIImageView中加载每个图像的最佳做法是什么? 特别是,我应该在下载后resize/替换UIImageview,还是应该调整图像大小以适应UIImageView。 请注意,resize/替换UIImageView也会resize/替换UITableViewCell。 它会引起任何问题吗?

几点想法:

下载多个图像并在UIImageView内部的UIImageView加载每个图像的最佳做法是什么?

有关下载图像的最佳做法包括:

  1. 绝对可以利用延迟加载(在需要时加载图像而不是之前加载图像)。

  2. 异步下载图像。

  3. 确保您的下载技术将取消对不再可见的tableview单元格的请求。 例如,如果您使用的是慢速网络并在桌面视图中快速向下滚动,则不希望系统下载不再可见的图像。

  4. 确保您没有为服务器发出太多并发请求。 在iOS中,当您超过5或6个并发请求时,后续请求将冻结,直到前一个请求完成。 在最坏的情况下,后续请求实际上会在超时时开始失败。

  5. 缓存结果。 至少,将它们缓存在内存中。 您可能还想将它们缓存到持久存储(也称为“磁盘”)。

如果您要为异步操作,缓存等编写自己的代码,您可能希望使用NSOperationQueue而不是GCD,以便限制后台请求的数量并使请求可取消 。 您将使用NSCache来缓存图像。 并且您可能使用UITableViewCell子类(或类别),以便您可以保存对“先前”操作的weak引用,以便您可以取消任何不完整的先前请求。

正如您所看到的,这是非常重要的,我建议您使用现有的UIImageView类别,例如可用作SDWebImageAFNetworking一部分。 恕我直言,前者更富有(例如提供磁盘缓存),但如果你做了很多网络并且想要坚持使用单一框架, AFNetworking也做得很好。

后来你问:

特别是,我应该在下载后resize/替换UIImageview,还是应该调整图像大小以适应UIImageView。 请注意,resize/替换UIImageView也会resize/替换UITableViewCell。 它会引起任何问题吗?

  1. 如果您的图像大于单元格缩略图视图所需的图像,则有两种方法。 首先,您可以使用UIViewContentModeScaleAspectFitUIViewContentModeScaleAspectFillcontentMode (如果您使用AspectFill ,请确保您还将clipsToBounds设置为YES )。 更好的是,您可以在下载后实际调整图像大小 。

  2. 这是个人观点,但我认为在单元格上安装固定大小的UIImageView是一个更好的用户体验,然后在完成异步图像下载时,只需设置UIImageViewimage属性即可。 您希望图像在下载时优雅地显示在UI中,但是当用户已经在阅读那里的内容时,您通常不希望对视图进行重新布局。 如果您的设计绝对需要重新布局单元格,那么您只需调用reloadRowsAtIndexPaths

UITableViewCell延迟加载图像的常见做法是使用通知回调让UITableViewCell知道何时接收到图像。

本质上,您将要创建一个UIImageView的子类,该子类具有imageURL字段,当更改时,它会触发对图像的请求,并使用它而不是标准的UIImageView

UIImageView子类的接口:

 @property (nonatomic, copy) NSString *imageURL; 

UIImageView子类的实现:

 //synthesize property @synthesize imageURL = _imageURL; - (void)setImageURL:(NSString *)imageURL { if(_imageURL) [[NSNotificationCenter defaultCenter] removeObserver:self name:_imageURL object:nil]; _imageURL = [imageURL copy]; //if imageURL is valid... if(_imageURL.length) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveImage:) name:_imageURL object:nil]; //fire off some asynchronous image fetch //when the image fetch completes, sent off a notification using the imageURL as the notification name //It's up to you to create the implementation for this yourself ... [MyImageManager fetchImage:_imageURL notificationName:_imageURL]; } } - (void)didReceiveImage:(NSNotification*)notification { //handle your received image here if([notification.object isKindOfClass:[UIImage class]]) { self.myCustomImageView.image = notification.object; } } 

当你覆盖prepareForReuse时,在UITableViewCell类中:

 - (void)prepareForReuse { [super prepareForReuse]; self.myCustomImageView.imageURL = nil; self.myCustomImageView.image = nil; //do the rest of your prepareForReuse here: ... } 

现在,就整个图像重新调整尺寸和调整图像视图的大小而言,你应该做的就是单独保留imageView的大小,并使用contentMode属性来处理结果图像的不同大小。 您可能的值是:

 UIViewContentModeScaleToFill, UIViewContentModeScaleAspectFit, UIViewContentModeScaleAspectFill, UIViewContentModeRedraw, UIViewContentModeCenter, UIViewContentModeTop, UIViewContentModeBottom, UIViewContentModeLeft, UIViewContentModeRight, UIViewContentModeTopLeft, UIViewContentModeTopRight, UIViewContentModeBottomLeft, UIViewContentModeBottomRight, 

每个都有各自的结果 – 你可能想要使用UIViewContentModeScaleAspectFit因为这将重新调整图像的大小以适应imageView,而不会扭曲它 – 这可能会留下空白边距到imageView的大小或顶部/底部。 Aspect填充将执行类似的操作,只是它会将图像调整为足够大以填充整个imageView,并且可能会切掉图像的边或顶部/底部。 缩放以填充将仅拉伸图像以填充imageView。