【问题标题】:Should Core Data Managed Object creation occur within the Managed Object Context's `performBlock:` call?Core Data Managed Object 创建是否应该发生在Managed Object Context 的`performBlock:` 调用中?
【发布时间】:2016-05-16 18:11:21
【问题描述】:

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

作为其中的一部分,我将initWithEntity:insertIntoManagedObjectContext: 的托管对象创建调用 performBlock: 块中,以便在 MOC 的私有队列上运行。

这符合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 方法中初始化托管对象,这些方法实际上在完成块中返回新创建的对象。

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

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

我的每个托管对象都执行以下操作,通过从 performBlock: 块中调用的完成块返回创建的对象。

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

    [managedObjectContextPrivateQueue save:&error]

    completion(managedObject);
}];

或者,是否可以在 performBlock: 块之外创建托管对象,并且只将插入/保存操作移到内部?注意NSEntityDescription方法确实需要访问块外的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: 等待块运行,然后直接从方法中返回托管对象,而不是从完成块中返回。

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

【问题讨论】:

  • 为什么不能将 'managedObjectFromJSON:` 消息放入块中?
  • 我为 NSManagedObject 找到的唯一初始化程序需要一个上下文 - 并将对象插入其上下文中。如果我理解正确,则此插入必须发生在 PerformBlock: 或 PerformBlockAndWait: 中,我希望我在这里错了,但是...

标签: ios objective-c multithreading core-data nsmanagedobject


【解决方案1】:

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

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

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

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

【讨论】:

  • 您能否详细说明如何创建 NSManagedObject 而无需在创建时将其插入 MOC?我看到的唯一初始化程序是 initWithEntity:insertIntoManagedObjectContext: 在创建时将对象插入其 MOC。请帮忙?
  • 您可以将自己的构造函数添加到您的NSManagedObject 子类中。
  • 但是那些构造函数应该调用[super init],不是吗?如果是这样 - 我回来了需要作为上下文的指定(也是唯一......)初始化程序......我看不到这里的重点。一个 NSManagedObject 不是一个普通的 NSObject,显然它的初始化是不同的,不能安全地覆盖和忽略。
猜你喜欢
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-26
  • 2011-01-04
  • 2012-04-07
  • 2010-11-19
相关资源
最近更新 更多