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

时间:2016-01-23 08:07:06

标签: ios swift uitableview

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

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300.0

通常情况下我会使用tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade),但这会调用cellForRowAtIndexPath方法,该方法再次调用我的图片下载方法。

我尝试拨打tableView.layoutIfNeeded()cell.layoutIfNeeded()cell.setNeedsLayout(),没有任何帮助。

我的问题是如何在不调用cellForRowAtIndexPath方法的情况下重绘表格视图单元格?

2 个答案:

答案 0 :(得分:2)

这里的根本问题是您下载图像的方式。您应该在代码中进行一些簿记,并跟踪哪些图像已经下载或已经下载。根据这一点,您可以决定是否应该开始新的下载。 不要试图破解这个,因为这将导致你以后很多痛苦(我从经验中知道)。 最好的方法是拥有某种数据对象,以及另一个进行下载的对象。然后,只要下载完成,此对象就会更新此图像的正确数据对象。然后这个下载器应该告诉你的dataSource这个数据对象已经更新。作为响应,您的dataSource可以重新加载该数据对象的indexPath。通过这种方式,您的dataSource永远不必担心下载,并且可以简单地检查数据对象并使用它来设置单元格上的值。如果有图像下载,它将使用它,否则没有图像(或某些占位符可能)。

现在,您可以将包含@(YES)或@(NO)的字典属性作为键的值或单元格的名称或indexPath保存为键。然而,这种方法很幼稚,因为它不会非常易于维护或移植(对于其他viewControllers或应用程序的部分),并且indexPath和image之间没有简单的转换。请记住,tableViewCells永远不能用作使用某些逻辑的数据源:它们是您拥有其他逻辑的终端点。这是因为它们被重复使用,并且基本上不可信任在某个位置。基于indexPaths所做的一切。 (并使用tableview获取单元格的indexPath。)

所以,现在你可以在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)
}

答案 1 :(得分:0)

如果您使用UIImageView显示图片,则无需重新绘制单元格,只需在图片下载完成后设置图片属性即可。

如果您自己在自定义UIView子类上绘制图像,则可以在该视图上调用setNeedDisplay方法,该方法将视图标记为脏,并在下一个周期重绘。 / p>

但是,最好的方法是改进cellForRowAtIndexPath:并在模型对象中设置downloading标志,并且仅在未设置该标志时才开始下载。