将NSManagedObject与另一个NSManagedContext中的“相同”NSManagedObject合并(多线程)

时间:2011-08-18 19:58:17

标签: multithreading core-data nsmanagedobject nsmanagedobjectcontext

我有两个处于1:n关系的实体。在这个问题中,我将使用公司雇员。在我的应用程序中,您可以创建一个新的公司并自动找到他们的员工

我创建了许多线程,这些线程都有自己的NSManagedObjectContext。在这些主题中,我创建了一个新员工。我可以创建新的员工(在一个帖子中),然后使用mergeChangesFromContextDidSaveNotification:合并这两个上下文。

问题在于我不知道在哪里创建新的公司。如果我在主题中创建并添加新的 employees ,我会为每个员工获得一个公司。

如果我在创建雇员之前创建公司(在他们自己的主题中),那么公司就是错误的{{1} }。我无法将公司对象从主NSManagedObjectContext移动到线程中的对象。 我找到了一种方法将公司复制到帖子的NSManagedObjectContext,但在合并上下文时,我有一个公司,一个员工,一个有两个,一个有三等等。

您可以说我可以创建所有员工,并在创建后将其添加到一家新公司。但我不希望这样,因为我已将实体绑定到NSManagedObjectContext以便将它们呈现在两个TableView中。我想在创建新员工后立即更新tableview。

我还希望能够更新公司并寻找新的员工。至少在这一点上,我需要一个已经存在的公司来刷新它。因此,我必须以某种方式得到它并在不同时从两个线程更改它的情况下进行更改...

这个问题让我发疯。现在坐了两天。有人可以帮助我吗?

修改:使用NSArrayController时,是否有可能以某种方式说它始终是同一家公司?

Edit2:以下是我在评论中谈到的测试应用:http://www.file-upload.net/download-3674327/CoreDataMultiThreading.zip.html

非常感谢!

(请原谅我的发音)

1 个答案:

答案 0 :(得分:3)

我有几乎完全相同的问题,我认为这可能是CoreData架构中存在的最大问题之一:(

线程与核心数据不兼容。我通常最终得到一个核心数据“编写器”线程,所有其他线程只能从持久性存储中读取(在编写器线程更新时自行更新)。 (实际上,我使用NSOperationQueue和NSOperation子类来处理线程,但它基本相同 - 只要一次只有一个线程写入我就可以了)

您的问题有两种解决方案。

您可以先创建公司并将其保存到持久存储中,然后再触发任何线程。然后,制作员工的所有线程都可以在各自的NSManagedObjectContexts中检索同一个公司。要确保所有线程在其NSManagedObjectContexts中都具有相同公司,请将公司的NSManagedObjectID传递给每个线程,并使用objectWithID:从本地NSManagedContext检索它。 (在多个线程中使用CoreData的规则之一是永远不会传递托管对象,始终传递ID并为每个线程获取一个新副本)

另一个解决方案是执行所有可能会按顺序执行碰撞操作的核心数据写入操作(我最喜欢的解决方案) - 这将确保第一个操作使公司和其他操作只使用现有的操作

希望有所帮助!


编辑在线程示例之间移动对象

此方法将创建公司并为您提供托管对象ID

// Create the company and save it. 
- (NSManagedObjectID *)createCompanyOnThreadOne {
     NSManagedObject *company = [NSEntityDescription insertNewObjectForEntityForName:@"Company" inManagedObjectContext:context];
     [company setName:@"My Company"];
     [[company managedObjectContext] save:nil];
     return [company objectID];
}

//然后,对于要添加员工的每个后台线程,传入对象ID:

// Create the company
ManagedObjectID *companyID = [self createCompanyOnThreadOne];

// Create three employees
[self performSelectorInBackground:@selector(createEmployee:) withObject:companyID];
[self performSelectorInBackground:@selector(createEmployee:) withObject:companyID];
[self performSelectorInBackground:@selector(createEmployee:) withObject:companyID];

//在后台运行的方法看起来像

- (void)createEmployee:(NSManagedObjectID *)companyID {
    NSManagedObjectContext *context = ... get a new context for this thread here ... 

    // Get the company from the persistent store
    NSManagedObject *company = [context objectWithID:companyID];

    // Make your employee and save it
    NSManagedObject *employee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:context];
    [employee setCompany:company];

    // Save it
    [context save:nil];
}

但是,我不建议同时写这么多线程 - 它会变得混乱 - 如果两个线程同时将一个员工添加到公司会发生什么 - 我打赌一个线程将保存好并且第二个帖子会告诉你合并冲突吗?我想你会发现的。