我有一个 UITableView,它在 UITableView 中异步加载图像。由于所有图片的高度都不一样,所以我根据图片的高度设置了高度限制。
这在我使用 DataWithContentsOfUrl 时工作正常,但会卡住 UI。当我异步加载时,图像像这样堆叠在一起:
http://i.stack.imgur.com/TEUwK.png
我使用的代码如下:
NSURL * imageURL = [NSURL URLWithString:img];
NSURLRequest* request = [NSURLRequest requestWithURL:imageURL];
cell.imageViewHeightConstraint.constant=0;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) {
if (!error){
UIImage *imgz = [UIImage imageWithData:data];
[cell.CellImg setBackgroundImage:imgz forState:UIControlStateNormal];
[cell.CellImg sizeToFit];
cell.imageViewHeightConstraint.constant=result.width*(imgz.size.height/imgz.size.width);
[cell setNeedsUpdateConstraints];
}
}];
[cell updateConstraints];
当我上下滚动几次时,图像会正确定位。
最佳答案
问题没有指定不同图像尺寸的期望行为。单元格应该变高以适应单元格,还是单元格内的 ImageView (看起来像代码中的按钮)?
但我们应该暂时搁置这个问题,着手解决代码中更严重的问题:它从 cellForRowAtIndexPath
发出一个不 protected 网络请求。结果,(a) 用户来回滚动会生成许多冗余请求,并且 (b) 用户快速滚动很长一段路会生成一个请求,当启动它的单元格消失时,该请求得到满足 - 作为单元格重用对于另一行。
为了解决 (a),数据源应该缓存获取的图像,并且只请求那些还没有收到的图像。为了解决 (b),完成 block 不应直接引用单元格。
一个简单的缓存看起来像这样:
@property(strong,nonatomic) NSMutableDictionary *images;
// initialize this when you initialize your model
self.images = [@{} mutableCopy];
// move the network code into its own method for clarity
- (void)imageWithPath:(NSString *)path completion:(void (^)(UIImage *, NSError *))completion {
if (self.images[indexPath]) {
return completion(self.images[indexPath], nil);
}
NSURL *imageURL = [NSURL URLWithString:path];
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error){
UIImage *image = [UIImage imageWithData:data];
self.images[indexPath] = image;
completion(image, nil);
} else {
completion(nil, error);
}
}];
}
现在,我们通过首先在 cellForRowAtIndexPath 中检查缓存中的图像来解决多请求问题。
UIImage *image = self.images[indexPath];
if (image) {
[cell.CellImg setBackgroundImage:image forState:UIControlStateNormal];
} else {
// this is a good place for a placeholder image if you want one
[cell.CellImg setBackgroundImage:nil forState:UIControlStateNormal];
// presuming that 'img' is a string from your mode
[self imageWithPath:img completion:^(UIImage *image, NSError *error) {
// the image is ready, but don't assign it to the cell's subview
// just reload here, so we get the right cell for the indexPath
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}];
}
还要注意在完成 block 中没有做什么...我们通过不引用单元来修复单元重用。相反,我们知道图像现在已缓存,我们重新加载 indexPath。
回到图像大小:大多数应用程序喜欢看到表格 View 单元格随着可变高度 subview 变高或变短。如果是这种情况,那么您根本不应该对该 subview 施加高度限制。相反,将它的顶部和底部边缘约束到单元格的内容 View (或者将它包含在 subview 链中,这些 subview 相互约束顶部和底部并包含最顶部和最底部的 subview 顶部和底部边缘到单元格)。然后(我认为在 iOS 5+ 中),这将允许您的单元格使用该 subview 约束链更改高度...
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = // your best guess at the average height here
关于ios - 使用自动布局在 UITableView 中异步加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32036290/