这是问题:我在保存并将缩略图提取到Core Data后更新我的tableview,然后我告诉单元格自行更新 - 因此它可以在图像加载到Core Data时显示缩略图。我使用两个不同的线程,因为Core Data不是线程安全的,当然所有GUI元素都需要在主线程中发生。
但是整个方法只是永远循环,导致它的原因是当我重新加载线程时:
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
为什么呢?以及如何解决此问题?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Photo"];
Photo *photo = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = photo.title;
cell.detailTextLabel.text = photo.subtitle;
NSLog(@"Context %@", self.photographer.managedObjectContext);
[self.photographer.managedObjectContext performBlock:^{
[Photo setThumbnailForPhoto:photo];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData:photo.thumbnail];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
});
}];
return cell;
}
答案 0 :(得分:3)
在加载fetch并调用某个单元格的重载后,再次调用cellForRowAtIndexPath:
会导致无限循环。
重新加载会强制再次调用cellForRowAtIndexPath:
...并且在您的情况下一次又一次地调用无穷大。
解决方案很简单......不要在cellForRowAtIndexPath中重新加载您的单元格,而是在fetchrequest的回调方法中重新加载。然后在那里重新加载它,而不是创建单元格。
而不是根本不在cellForRowAtIndexpath:
内加载图像。
每当您的表被实例化时,创建一个循环数据源并获取每个项目的相应单元格的方法。然后为您认为需要的每个单元格加载图像。每当完成项目的提取时重新加载单元格(例如回调方法)。
如果您确实希望像现在一样在图像的创建中加载图像(虽然我认为这不是正确的方法)。您可以使用if语句检查整个performBlock:是否已设置图像。
答案 1 :(得分:1)
正如其他人已经说过的那样,在加载图像时不需要调用reloadRowsAtIndexPaths
。将新图像分配给cell.imageView.image
就足够了。
但您的代码还有另一个问题。我假设self.photographer.managedObjectContext
是“私有并发类型”的托管对象上下文,因此performBlock
在后台线程上执行。 (否则就不需要使用dispatch_async(dispatch_get_main_queue(), ...)
。)
所以performBlock:
在后台线程上异步执行代码。 (这很好,因为UI没有被阻止。)但是当一段时间后取出图像时,该单元可能已被重用用于另一行。 (如果滚动表格视图,以便在获取图像时该行变为不可见,则会发生这种情况。)
因此,您必须检查单元格是否仍然在tableview中的相同位置:
[self.photographer.managedObjectContext performBlock:^{
[Photo setThumbnailForPhoto:photo];
dispatch_async(dispatch_get_main_queue(), ^{
if ([[tableView indexPathForCell:cell] isEqualTo:indexPath]) {
cell.imageView.image = [UIImage imageWithData:photo.thumbnail];
}
});
}];
答案 2 :(得分:1)
我将替换以下代码:
cell.imageView.image = [UIImage imageWithData:photo.thumbnail];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
使用:
UITableViewCell *blockCell = [tableView cellForRowAtIndexPath:indexPath];
blockCell.imageView.image = [UIImage imageWithData:photo.thumbnail];
[blockCell setNeedsLayout];
这解决了递归重新加载的问题,以及cell
在过渡期间重用的可能性。我还会检查你是否已经加载了照片数据,如果是的话也不会更新。
由于您使用的是NSFetchedResultsController
,如果代理回调已经在照片数据更新时通知您,您可能最好使用Totomus Maximus的回答。这种方式只是更新图像视图,不会更新Photo更新方法可能更改的任何其他信息。