【问题标题】:Magical Record create/fetch entity in separate threadMagical Record 在单独的线程中创建/获取实体
【发布时间】:2013-05-15 18:03:38
【问题描述】:

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

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

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

或者在保存时获取/创建什么线程真的无关紧要吗?

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

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

【问题讨论】:

    标签: ios core-data nsmanagedobjectcontext nsoperation magicalrecord


    【解决方案1】:

    让我们暂时忽略 MagicalRecord。要在多个线程上使用 Core Data,您需要注意一些事项。

    1. 切勿在线程之间传递NSManagedObject。相反,将 NSManagedObjectID 传递给您想要的对象,然后在后台线程中重新获取它。
    2. 负责任地构建您的NSManagedObjectContext。这意味着您必须了解initWithConcurrencyType: 的含义。我们将深入探讨。

    主线程

    您的主要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,但由于您尚未调用保存,因此数据尚未持久化。在您的队列 KVO 中,您可以通过排队保存块来调用主上下文的保存。

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

    【讨论】:

    • MagicalRecord 会为您处理所有上下文管理工作。
    • MagicalRecord 使用块管理后台工作。与任何围绕 Core Data 的第三方包装器一样,它本质上不如单独使用 Core Data 灵活。希望我试图解释幕后发生的事情仍然有用。
    • 解释得很好!我认为这应该是公认的答案。
    猜你喜欢
    • 1970-01-01
    • 2016-01-18
    • 2013-08-02
    • 1970-01-01
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    相关资源
    最近更新 更多