Magical Record在单独的线程中创建/获取实体

时间:2013-05-15 18:03:38

标签: ios core-data nsmanagedobjectcontext nsoperation magicalrecord

我有一堆NSOperations需要在队列中运行时创建和获取实体。

  1. 在NSOperations中创建实体时,我可以简单地使用默认上下文创建,或者因为我在主线程上没有新线程,这是不允许/建议的?如果我在这个线程上创建一个新实体,那么将它合并回默认上下文的最佳方法是什么(而不是保存到商店)?

  2. 在获取这些线程时,我需要获取然后更新该实体中的数据。我不知道如何做到这一点然后合并到默认上下文。

  3. 或者,当您保存时,您获取/创建的线程是否真的无关紧要?

    我说上面的默认上下文是因为我有NSFetchedResultsControllers监视更新和插入的默认上下文。目前我的解决方案是在主线程上完成所有这些工作,但是应用程序现在开始爬行,现在正在通过它运行大量数据。

    我还有一个类监控(通过KVO)操作队列计数。一旦它变为零,我就预先形成一个保存。我宁愿只在完成所有上述NSOperations后执行,就像我现在正在执行的那样。谢谢你的帮助。

1 个答案:

答案 0 :(得分:8)

现在让我们忽略MagicalRecord。要在多个线程上使用Core Data,您需要了解一些事项。

  1. 永远不要在线程之间传递NSManagedObject。相反,传递所需对象的NSManagedObjectID,然后在后台线程中重新获取它。
  2. 负责任地构建您的NSManagedObjectContext。这意味着您必须了解initWithConcurrencyType:的含义。我们将进入那个。
  3. 主线程

    您的主NSManagedObjectContext应使用并发类型NSMainQueueConcurrencyType构建。这将允许您利用内置队列中的上下文来执行串行操作。只要后台线程与主要上下文交互,您就应该使用performBlockperformBlockAndWait来完成工作。

    - (NSManagedObjectContext *)managedObjectContext 
    {
        if (_managedObjectContext != nil) {
            return _managedObjectContext;
        }
    
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (coordinator != nil) {
            _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
            [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        }
    
        return _managedObjectContext;
    }
    

    后台主题

    每当你在后台线程中工作时,你需要启动一个新的上下文。您不应该在线程之间共享上下文。将对主线程上下文的引用传递到操作中,并在操作开始后构建后台上下文。这将确保它构建在您将执行工作的线程上。

    - (NSManagedObjectContext *)newBackgroundManagedObjectContext
    {    
        // Create new context with private concurrency type
        NSManagedObjectContext *newContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [newContext setParentContext:self.mainContext];
    
        // Optimization
        [newContext setUndoManager:nil];
    
        return newContext;
    }
    

    将此背景上下文视为便笺簿。无论你做什么,都会留在那里,直到你拯救。由于您设置了parentContext,因此对背景上下文的保存会将更改合并到主上下文中。这将更新NSFetchedResultsController,但由于您尚未调用save,因此数据尚未保留。在队列KVO中,您可以通过排队保存块来调用主上下文中的保存。

    [self performBlock:^{
        NSError *error;
        [self save:&error];
        if (error) {
            // handle errors
        }
    }];