ios - 在后台线程上将核心数据图像加载到 UITableViewCell 时崩溃

标签 ios objective-c core-data uitableview

我在 Core Data 中存储了一系列个人资料图片作为 Binary Data(启用了 Allows External Storage 选项,所以不要指责我存储图片在核心数据 :)

每张图片都显示在 UITableViewCell 中。目前,当用户点击显示表格 View 时会有轻微的延迟,大概是因为它是从 Core Data 加载它们,这对性能有足够的影响,可以在主线程上加载它们时锁定 UI。

我想将图像加载到一个单独的后台线程,以便立即显示表格 View ,并在从 Core Data 加载图像时显示图像。

我试过解决方案 in this post-cellForRowAtIndexPath: 方法中使用以下代码:

    // Create the cell
    MyCell *cell = [tableView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {

        // Get a reference to the object for this cell (an array obtained from Core Data previously in the code)
        MyObject *theObject = [self.objectArray objectAtIndex:indexPath.item];

        // Load the photo from Core Data relationship (ProfilePhoto entity)
        UIImage *profilePhoto = [UIImage imageWithData:theObject.profilePhoto.photo];

        // Set the name
        cell.nameLabel.text = theObject.name;

        dispatch_sync(dispatch_get_main_queue(), ^(void) {

            // Set the photo
            cell.photoImageView.image = profilePhoto;

        });

    });

    // Return the cell
    return cell;

但是,应用程序崩溃并出现以下错误(对 TableView 中的每一行重复):

CoreData: error: exception during fetchRowForObjectID: statement is still active with userInfo of (null)

如能帮助理解和解决此问题,我们将不胜感激。

最佳答案

solution which Marcus Zarra provided给了我一个关于如何解决这个问题的想法,但我认为将我实现的代码发布给任何其他寻求解决方案的人是值得的。所以,这是我为 -cellForRowAtIndexPath: 方法编写的新代码:

// Create the cell
MyCell *cell = [tableView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];

// Get a reference to the object for this cell
MyObject *theObject = [self.objectArray objectAtIndex:indexPath.item];

// Reset the image
cell.imageView.image = nil;

// Set the name
cell.nameLabel.text = theObject.name;

// Check if the object has a photo
if (theObject.profilePhoto != nil) {

    // Create a new managed object context for the background thread
    NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    backgroundContext.parentContext = self.managedObjectContext;

    // Perform the operations on the new context
    [backgroundContext performBlockAndWait:^{

        // Fetch the object
        NSError *error;
        ProfilePhoto *profilePhotoObject = (ProfilePhoto *)[backgroundContext existingObjectWithID:theObject.profilePhoto.objectID error:&error];

        // Create the image
        UIImage *thePhoto = [UIImage imageWithData:myObject.profilePhoto];

        dispatch_async(dispatch_get_main_queue(), ^(void) {

            // Set the photo
            cell.imageView.image = thePhoto;

        });

    }];

}

return cell;

您还需要更改 App Delegate 文件中创建托管对象上下文的行:

_managedObjectContext = [[NSManagedObjectContext alloc] init];

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

否则 .parentContext 分配将不起作用。

希望这对遇到此问题的其他人有所帮助!

关于ios - 在后台线程上将核心数据图像加载到 UITableViewCell 时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21322605/

相关文章:

objective-c - [ClassName class] 背后发生了什么?

ios - mergeChangesFromContextDidSaveNotification 后的 KVO 通知

objective-c - 地幔和核心数据 : Only one Model

ios - iOS 11 上的控制台日志垃圾邮件

android - 创建 QR 码以在 iPhone 和 Android 上发送电子邮件

ios - 多次缩放后图像缩小

ios - UITableView 单元格在初始化时不为零

ios - 表格 View 单元格仅在屏幕外时自动布局

ios - 需要有关以编程方式创建自动布局约束的帮助

ios - NSFetchedresultsController 部分 Name KeyPath 基于当前位置和其他位置之间的范围