ios - 是否应该在托管对象上下文的 `performBlock:` 调用中创建核心数据托管对象?

标签 ios objective-c multithreading core-data nsmanagedobject

我最近开始尝试 Core Data 较新的托管对象上下文的 initWithConcurrencyType:NSPrivateQueueConcurrencyType 构造。当使用这种类型的 MOC 时,我们应该使用 performBlock:performBlockAndWait: 来“确保 block 操作在为上下文指定的队列上执行。”

作为此过程的一部分,我将 initWithEntity:insertIntoManagedObjectContext: 的托管对象创建调用移至 performBlock: block 内,以便在其上运行MOC 的私有(private)队列。

这与 Apple's Core Data Concurrency 中所示的策略匹配文章:

[private performBlock:^{
    for (NSDictionary *jsonObject in jsonArray) {
        NSManagedObject *mo = ... ; //Managed object that matches the incoming JSON structure
    }
    NSError *error = nil;
    if (![private save:&error]) {
        NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
}];

我已经found myselfvoid 方法中初始化托管对象,这些方法实际上在完成 block 中返回新创建的对象。

+ (void)managedObjectFromJSON:(NSDictionary *)json completion:(void (^)(XYZManagedObject *object))completion;

与简单地从 JSON 解析方法返回对象相比,这种架构引入了复杂性。我似乎还遇到了与此设计相关的并发问题/崩溃,可能是在这些完成 block 构造函数中链接在一起的关系托管对象的异步加载中。

我的每个托管对象都执行如下所示的操作,通过从 performBlock: block 内调用的完成 block 返回创建的对象。

[managedObjectContextPrivateQueue performBlock:^{
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"entity" inManagedObjectContext:managedObjectContextPrivateQueue];
    XYZManagedObject *managedObject = [[XYZManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:managedObjectContextPrivateQueue];

    [managedObjectContextPrivateQueue save:&error]

    completion(managedObject);
}];

或者,是否可以在 performBlock: block 外部创建托管对象,并且仅将插入/保存操作移至内部?请注意,NSEntityDescription 方法确实需要访问 block 外的 MOC。

NSEntityDescription *entity = [NSEntityDescription entityForName:@"entity" inManagedObjectContext:managedObjectContextPrivateQueue];
XYZManagedObject *managedObject = [[XYZManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

[managedObjectContextPrivateQueue performBlock:^{
    [managedObjectContextPrivateQueue insertObject:managedObject];
    [managedObjectContextPrivateQueue save:&error]
}];

return managedObject;

或者,也许我应该使用 performBlockAndWait: 等待 block 运行,然后直接从方法而不是从完成 block 返回托管对象。

当托管对象上下文调用应通过 performBlock: 私有(private)队列路由时,应如何创建和返回托管对象?

最佳答案

您可以在 MOC 之外创建托管对象。参见 -[NSManagedObjectContext insertObject:]

但是,您可能一般不想这样做。如果你想创建一个有条件的对象,这很有用。例如,如果您有一个表示用户可能编辑的内容的托管对象,您可以创建一个非托管版本用于编辑,并且仅在用户保存更改时插入到 MOC 中。这不是最好的方法,但很有效。

但是,您的问题实际上是关于 MOC 的异步操作。我的意见是,最好的办法是查看每个处理托管对象的 API,并弄清楚如何使它们正确异步。您绝对应该从方法返回托管对象,除非您知道调用方正在同一 MOC 的 performBlock{AndWait}: 中运行。这是因为无法(可靠地)从创建它们的 MOC 外部访问托管对象。

您可以返回 objectID,并让调用者获取关联的对象。它通常更乏味且效率更低,但它是跨越 MOC 边界时唯一可靠的解决方案。

关于ios - 是否应该在托管对象上下文的 `performBlock:` 调用中创建核心数据托管对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37260462/

相关文章:

objective-c - 指定 NSDictionary 条目的值类型

android - 无法处理 webservice 方法调用中的线程?

java - 动态加载 GridPane 时显示 ProgressBar

linux - 如何实际查找 UNIX 上进程的死锁原因?

ios - 如何使用页面控件在 iOS 中开发部分

ios - NSURLSessionConfiguration 和 NSURLRequest 的相同属性?

ios - 我应该避免在全局队列中创建 JSContexts 吗?

ios - 线程 1 exc_bad_instruction (code=exc_i386_invop subcode=0x0) error while clicking sth nil

iphone - NSString 到 NSNumber 的格式

ios - 无法使用 facebook new sdk 3.11 将链接和图像发布到 friend 墙上