重绘表视图单元格而不调用单元格ForRowAtIndexPath



我将异步加载图像并将其设置为表视图单元格。问题是我对我的单元格使用自动布局,所以我希望表格视图在设置图像后重绘单元格。

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标志,并且仅在未设置该标志时才开始下载。

最新更新