在后台线程保存到CoreData上下文中

9

我已经苦恼了一段时间,但是苹果的文档和stackoverflow都没有帮助到我。我之前使用的是UIManagedDocument上的ManagedObjectContext并且下面的代码可以正常工作。后来我决定在AppDelegate中使用Apple的CoreData模板,所以model、persistent store coordinator和context都是在AppDelegate中创建的。使用AppDelegate的context进行获取没有问题,但是在保存时有问题。根据Apple的建议,我应该在保存的线程上拥有本地context,并且使用相同的持久化存储协调器。但是以下代码实际上并没有保存数据。请问这里是否有人可以提供建议?谢谢。

- (void)fetchAndPersist
{
    dispatch_queue_t ffetchQ = dispatch_queue_create("ForFetch", NULL);
    dispatch_async(ffetchQ, ^{

        NSManagedObjectContext *secureManagedObjectContext;
        NSPersistentStoreCoordinator *coordinator = [appDelegate persistentStoreCoordinator];
        if (coordinator != nil) {
            secureManagedObjectContext = [[NSManagedObjectContext alloc] init];
            [secureManagedObjectContext setPersistentStoreCoordinator:coordinator];
        }

        // find missing date
        DataManager *dataManager = [[DataManager alloc] init];
        NSDate *missingDate = [dataManager findMissingDateFromDate:selectedDate inContext:secureManagedObjectContext];

        if (missingDate) {
            // fetch and parse data
            DataFetcher *dataFetcher = [[dataFetcher alloc] init];
            NSDictionary *fetchResponse = [dataFetcher parseDataForDate:missingDate];

            // persist it in a block and wait for it
            [secureManagedObjectContext performBlock:^{
                DataStore *dataStore = [[DataStore alloc] init];
                BOOL parsingError = [dataStore persistData:fetchResponse inContext:secureManagedObjectContext];

                if (parsingError) {
                    // handle error
                } else {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        // perform on main
                        [self fetchAndPersist];
                    });
                }
            }];
        }
    });
}

为什么要在另一个线程中保存?在这种情况下,这真的是必要的吗? - DogCoffee
如果你所说的“在另一个线程中保存”的意思是performBlock操作,那么不是这样的。我所需要的只是最简单的获取和持久化操作,可以在主线程之外执行。 - Martin Koles
澄清一下,目前的代码会崩溃并报告“只能在使用队列创建的NSManagedObjectContext上使用-performBlock:”。如果我注释掉performBlock行,代码将在无限循环中运行,因此主线程看不到已保存的数据。 - Martin Koles
2个回答

18

3
你的崩溃是因为你的NSManagedObjectContext正在使用旧的Core Data并发过时的线程限制模型

secureManagedObjectContext = [[NSManagedObjectContext alloc] init];

init只是一个包装器,它使用参数NSConfinementConcurrencyType调用initWithConcurrencyType:。这将使用线程限制模型创建上下文,该模型无法使用performBlock:performBlockAndWait:。只有使用较新(不过时!)队列限制模型的上下文才能使用这些方法,并且必须使用这些方法来访问上下文或属于它的对象。要使用队列限制和私有队列创建上下文:

secureManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

如果你的代码已经迁移到使用私有队列上下文,那么你也可以删除串行调度队列,因为私有队列上下文提供了相同的功能。


1
你说的“必须使用这些方法来访问上下文或属于它的对象”是什么意思?我正在使用新的并发类型,而且根本不需要使用performBlock和performBlockAndWait来使用上下文来保存/获取数据。也许我误解了? - Brian
是的,您必须使用这些方法才能获得正确的行为。https://developer.apple.com/library/ios/releasenotes/DataManagement/RN-CoreData/ - quellish

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