我将异步加载图像并将其设置为表视图单元格。问题是我对我的单元格使用自动布局,所以我希望表格视图在设置图像后重绘单元格。
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300.0
在通常情况下,我会使用 tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
,但这调用cellForRowAtIndexPath
方法,该方法再次调用我的图像下载方法。
我试着打电话给tableView.layoutIfNeeded()
,cell.layoutIfNeeded()
,cell.setNeedsLayout()
,没有任何帮助。
我的问题是如何在不调用方法的情况下重绘表视图单元格cellForRowAtIndexPath
?
这里的根本问题是下载图像的方式。您应该在代码中进行一些簿记,并跟踪哪个图像已经在下载或已经下载。根据这一点,您可以决定是否应该开始新的下载。不要试图解决这个问题,因为这会在以后给你带来很多痛苦(我从经验中知道)。最好的方法是拥有某种数据对象,以及另一个执行下载的对象。然后,每当下载完成时,此对象都会更新此映像的正确数据对象。然后,此下载器应告诉您的数据源此数据对象已更新。作为响应,您的数据源可以重新加载该数据对象的 indexPath。这样,您的 dataSource 就不必担心下载,只需检查数据对象并使用它来设置单元格上的值。如果下载了图像,它将使用它,否则没有图像(或者可能是某些占位符)。
现在,您可以保留一个字典属性,其中包含 @(YES) 或 @(NO) 作为 URL 的值,或者单元格的名称或 indexPath 作为键。然而,这种方法很幼稚,因为它不是很可维护或可移植(到应用程序的其他视图控制器或部分),并且 indexPath 和图像之间的转换并不容易。请记住,tableViewCells永远不能用作使用某些逻辑的数据源:它们是您拥有的其他逻辑将数据放置到的端点。这是因为它们是重用的,基本上不能被信任处于某个位置。你所做的一切都基于indexPaths。(并使用表视图获取单元格的索引路径)。
所以,现在你可以做cellForRowAtIndexPath:
NSString * imageURL = ....
NSNumber * downloading = self.imageDownloads[imageURL];
if (!downloading.boolValue)
{
self.imageDownloads[imageURL] = @(YES);
// start your download
}
- (void) imageDownloadedForURL: (NSString *) imageURL
{
self.imageDownloads[imageURL] = @(YES); // this is redundant
[self.tableView reloadRowAtIndexPaths: @[indexPathForThisImage]];
}
- (void) imageDownloadForULRFailed: (NSString *) imageURL
{
self.imageDownloads[imageURL] = @(NO);
// trigger a new download? (but be careful not to DDOS your server this way)
}
如果您使用UIImageView
来显示图像,则无需重绘单元格,只需在图像完成下载时设置 image 属性即可。
如果要在自定义UIView
子类上自己绘制图像,则可以在该视图上调用 setNeedDisplay
方法,该方法会将视图标记为脏视图,并将在下一个周期中重绘。
但是,最好的方法是改进cellForRowAtIndexPath:
并在模型对象中设置downloading
标志,并且仅在未设置该标志时才开始下载。