UIManagedDocument嵌套上下文

3
我一直在阅读苹果文档,但仍有一个问题,我找不到答案。我有一个UIManagedDocument对象,其中有两个嵌套的上下文——主线程上的子上下文和私有线程上的父上下文。接着,我还有一个服务器端。因此,当数据从服务器到达时,我想将其插入到我的托管文档中,并在后台线程中完成。
如果创建异步队列,在其中创建NSManagedObjectContext并将其设置为UIManagedDocument的子上下文(它是在主线程上创建的),这样做是否是安全的?
dispatch_queue_t fetchQ = dispatch_queue_create("Data fetcher", NULL);
dispatch_async(fetchQ, ^{
     //here goes some code for downloading data from the server

    NSManagedObjectContext * backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [backgroundContext setParentContext:self.eventDatabase.managedObjectContext]; // is this thread safe?

    //some code for creating objects in backgroundContext

    NSLog(@"inserting data in background thread");


});
dispatch_release(fetchQ);

用其他话来说,如果在主线程创建的私有线程父级上创建了一个上下文,那么将其分配给该上下文是否是线程安全的?
2个回答

4

您正在使用私有并发类型。这意味着,您应该通过执行 performBlock 方法来在其自己的队列上运行代码。因此,如果您想这样做,应该像这样操作...

NSManagedObjectContext * backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.parentContext = self.eventDatabase.managedDocument;
backgroundContext.performBlock:^{
    //here goes some code for downloading data from the server
    //some code for creating objects in backgroundContext

    NSLog(@"inserting data in background thread");

    // Calling save on the background context will push the changes up to the document.
    NSError *error = nil;
    [backgroundContext save:&error];

    // Now, the changes will have been pushed into the MOC of the document, but
    // the auto-save will not have fired.  You must make this call to tell the document
    // that it can save recent changes.
    [self.eventDatabase updateChangeCount:UIDocumentChangeDone];
});

如果您想自己管理队列,可以使用限制 MOC(管理对象上下文),您应该使用 NSConfinementConcurrencyType 进行初始化,或者使用标准的 init,因为那是默认设置。然后,代码会像这样...
dispatch_queue_t fetchQ = dispatch_queue_create("Data fetcher", NULL);
dispatch_async(fetchQ, ^{
    backgroundContext.parentContext = self.eventDatabase.managedDocument;

    //here goes some code for downloading data from the server

    NSManagedObjectContext * backgroundContext = [[NSManagedObjectContext alloc] init];

    // Everything else is as in the code above for the private MOC.
});
dispatch_release(fetchQ);

顺便提一下,不要忘记调用 [backgroundContext save:&error] 否则更改将无法推送到父上下文。 - Jody Hagins
为什么他不直接使用UIManagedDocument的parentContex呢?这个context在后台运行。 - João Nunes

0

Andrew,managedobjectcontext不是线程安全的。为了实现你想要的功能,你必须创建一个子管理上下文,在子上下文中进行操作,然后在子上下文和父上下文中保存更改。请记住,仅保存会将更改推送到上一级。

NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[addingContext setParentContext:[self.fetchedResultsController managedObjectContext]];

[addingContext performBlock:^{
    // do your stuffs
    [addingContext save:&error];

    [parent performBlock:^{
        [parent save:&parentError];
    }];
}];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接