【发布时间】:2012-07-20 16:09:50
【问题描述】:
下载多个图像并将每个图像加载到 UITableViewCell 内的 UIImageView 中的最佳做法是什么?特别是,我应该在下载后调整/替换 UIImageview 的大小还是应该调整图像的大小以适合 UIImageView。请注意,调整/替换 UIImageView 也会调整/替换 UITableViewCell。它会引起任何问题吗?
【问题讨论】:
标签: ios uitableview uiimageview
下载多个图像并将每个图像加载到 UITableViewCell 内的 UIImageView 中的最佳做法是什么?特别是,我应该在下载后调整/替换 UIImageview 的大小还是应该调整图像的大小以适合 UIImageView。请注意,调整/替换 UIImageView 也会调整/替换 UITableViewCell。它会引起任何问题吗?
【问题讨论】:
标签: ios uitableview uiimageview
一些想法:
下载多个图像并将每个图像加载到
UIImageView(位于UITableViewCell中)的最佳做法是什么?
有关下载图像的最佳做法包括:
一定要利用延迟加载(根据需要而不是之前加载图像)。
异步下载图片。
确保您的下载技术将取消对不再可见的表格视图单元格的请求。例如,如果您的网络速度较慢并在表格视图中快速向下滚动,您不希望占用您的设备下载不再可见的图像。
确保不要对服务器发出过多的并发请求。在 iOS 中,当您超过 5 或 6 个并发请求时,后续请求将冻结,直到前面的请求完成。在最坏的情况下,后续请求实际上会因为超时而开始失败。
缓存您的结果。至少,将它们缓存在内存中。您可能还希望将它们缓存到持久存储(也称为“磁盘”)。
如果您要为异步操作、缓存等编写自己的代码,您可能希望使用 NSOperationQueue 而不是 GCD,以便我可以约束 number of background requests 并发出请求 cancelable。您将使用NSCache 来缓存图像。您可能会使用UITableViewCell 子类(或类别),以便您可以保存weak 对“先前”操作的引用,以便您可以取消任何不完整的先前请求。
如您所见,这很重要,我建议您使用现有的UIImageView 类别,例如作为SDWebImage 或AFNetworking 的一部分提供的类别。恕我直言,前者更丰富一些(例如,提供磁盘缓存),但如果您正在做大量网络工作并想坚持使用单一框架,AFNetworking 也可以做得很好。
稍后你问:
特别是,我应该在下载后调整/替换 UIImageview 的大小,还是应该调整图像的大小以适应 UIImageView。请注意,调整/替换 UIImageView 也会调整/替换 UITableViewCell。会不会有什么问题?
如果您的图像大于单元格的缩略图视图所需的大小,您有两种方法。首先,您可以使用UIViewContentModeScaleAspectFit or UIViewContentModeScaleAspectFill 中的contentMode(如果您使用AspectFill,请确保您还将clipsToBounds 设置为YES)。更棒的是,你下载后还可以resize the image。
这是个人意见,但我认为在单元格上有一个固定大小的UIImageView,然后当异步图像下载完成后,只需设置@987654351 的image 属性。 @。您希望图像在下载时优雅地出现在您的 UI 中,但您通常不希望在用户已经在阅读那里的内容时对视图进行不和谐的重新布局。如果您的设计绝对需要重新布局单元格,那么您可以致电reloadRowsAtIndexPaths。
【讨论】:
NSOperationQueue 和NSCache。更好的是,使用现有的 UIImageView 类别(SDWebImage 或 AFNetworking 的)来解决我在修改后的答案中列举的许多问题。
SDWebImage,现在对第三方库libwebp 的依赖无济于事,如果没有,你会得到一个神秘的@ 987654358@ 错误。我有posted an issue,所以希望他们能尽快解决这个问题。如果没有,我在他们引入这种不必要的依赖之前发布了关于如何返回到版本的评论。
SDWebImage,它现在应该可以像宣传的那样工作,没有任何关于缺少标题的奇怪错误。
在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;
}
}
然后在 UITableViewCell 类中重写prepareForReuse时:
- (void)prepareForReuse {
[super prepareForReuse];
self.myCustomImageView.imageURL = nil;
self.myCustomImageView.image = nil;
//do the rest of your prepareForReuse here:
...
}
现在,就图像的整体大小调整与图像视图的大小调整而言,您应该做的是不理会 imageView 的大小,并使用contentMode 属性来处理生成图像的不同大小.您的possible values 是:
UIViewContentModeScaleToFill,
UIViewContentModeScaleAspectFit,
UIViewContentModeScaleAspectFill,
UIViewContentModeRedraw,
UIViewContentModeCenter,
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,
每个都有各自的结果 - 您可能想要使用 UIViewContentModeScaleAspectFit,因为这将重新调整图像大小以适合 imageView,而不会扭曲它 - 这可能会在大小或顶部/底部留下空白边距的图像视图。 Aspect fill 会做类似的事情,只是它将图像调整为足够大以填充整个 imageView,并且可能会切断图像的侧面或顶部/底部。 Scale to fill 只会拉伸图像以填充 imageView。
【讨论】:
contentMode。我将编辑我的答案以反映这一点。