1

这就是问题所在:在将缩略图保存并获取到 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;
}
4

3 回答 3

3

cellForRowAtIndexPath:无限循环是在加载 fetch 并调用某个单元格上的 reload 后调用再次引起的。

重新加载将迫使cellForRowAtIndexPath:再次调用...在您的情况下一次又一次地调用到无穷大。

解决方案很简单...不要在 cellForRowAtIndexPath 中重新加载您的单元格,而是在 fetchrequest 的回调方法中重新加载。然后在那里重新加载它而不是创建单元格。

而是根本不加载里面的图像cellForRowAtIndexpath:。每当您的表被实例化时,请创建一个循环您的数据源并获取每个项目的相应单元格的方法。然后为您认为需要的每个单元格加载图像。并在获取项目完成时重新加载单元格(例如回调方法)。

如果您确实希望像现在所做的那样在单元格的创建中加载图像(尽管我认为这不是正确的方法)。您可以围绕整个 performBlock: 使用 if 语句检查图像是否已设置。

于 2013-03-20T15:14:57.373 回答
1

reloadRowsAtIndexPaths正如其他人已经说过的那样,加载图像时应该不需要调用。分配一个新图像cell.imageView.image就足够了。

但是您的代码还有另一个问题。我假设这self.photographer.managedObjectContext是“私有并发类型”的托管对象上下文,因此performBlock在后台线程上执行。(否则就没有必要使用了dispatch_async(dispatch_get_main_queue(), ...)。)

所以performBlock:在后台线程上异步执行代码。(这很好,因为 UI 没有被阻塞。)但是当图像在一段时间后被提取时,单元格可能已被重新用于不同的行。(如果您滚动表格视图以使该行在获取图像时变得不可见,则会发生这种情况。)

因此,您必须检查单元格是否仍在表格视图中的相同位置:

[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];
        }
    });
}];
于 2013-03-20T15:47:25.547 回答
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 的回答。这种方式只会更新图像视图,不会更新照片更新方法可能更改的任何其他信息。

于 2013-03-20T16:05:34.867 回答