使用 NSPersistentContainer 实现核心数据并发

Posted

技术标签:

【中文标题】使用 NSPersistentContainer 实现核心数据并发【英文标题】:Core Data concurrency with NSPersistentContainer 【发布时间】:2017-07-18 20:51:35 【问题描述】:

注意:我查看了类似的问题,但没有找到描述这种情况的问题。

我正在查看 Apple 提供的以下有关 Core Data 并发的示例代码 (https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html)

NSArray *jsonArray = …;
NSPersistentContainer *container = self.persistentContainer;
[container performBackgroundTask:^(NSManagedObjectContext *context) 
    for (NSDictionary *jsonObject in jsonArray) 
        AAAEmployeeMO *mo = [[AAAEmployeeMO alloc] initWithContext:context];
        [mo populateFromJSON:jsonObject];
    
    NSError *error = nil;
    if (![context save:&error]) 
        NSLog(@"Failure to save context: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    
];

在我的应用中,直到用户点击屏幕上的保存按钮后才开始保存。我该怎么做,在私有上下文是 VC 的属性的情况下,我应该使用子上下文代替吗?

NSArray *jsonArray = …; //JSON data to be imported into Core Data
NSManagedObjectContext *moc = self.persistentContainer.viewContext; //Our primary context on the main queue

NSManagedObjectContext *private = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[private setParentContext:moc];

[private performBlock:^
    for (NSDictionary *jsonObject in jsonArray) 
        NSManagedObject *mo = …; // WHICH CONTEXT TO USE?  <<<======
        //update MO with data from the dictionary
    
    NSError *error = nil;
    if (![private save:&error]) 
        NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    

然后,一旦用户点击保存,请执行以下操作:

NSManagedObjectContext *moc = self.persistentContainer.viewContext; //Our primary context on the main queue
   [moc performBlockAndWait:^
            NSError *error = nil;
            if (![moc save:&error]) 
                NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);
                abort();
            
        ];
    ];

还要注意上面示例中使用哪个 moc 的问题(

编辑:我最终做的是立即保存子上下文,以便表格只使用viewContext 来显示结果。如果用户随后退出而不保存,我将再次从viewContext 中删除所有结果。保存按钮仍然存在,但现在只设置了一个标志,指示不删除结果。

【问题讨论】:

你在使用 persistentContainer 吗?如果是这样使用容器的“performBackgroundTask”,容器内部会创建一个私有上下文。 请阅读我的问题,使用 'performBackgroundTask' 不适用。 【参考方案1】:

如果您有一页表单并且希望在用户按下保存按钮时保存它,那么只需从 textFields(或您输入的任何数据)中获取数据,然后使用 performBackgroundTask 将其放入核心数据中.由于数据仅在用户编辑时存储在文本字段中,如果用户推回,他的编辑将丢失。

如果您对包含许多用户可以创建、销毁或链接的不同实体的复杂文档进行大量更改,并且所有这些仅在用户按下保存时保存,那么您应该使用子上下文。您将根据子上下文中的值显示数据,但只有在用户按下保存时才会将这些更改推送到父上下文。这是一种非常罕见的情况,我个人从未遇到过这样做的需要。

我强烈怀疑您属于第一种情况。不要使用子上下文。使用performBackgroundTask 并在用户按下保存时保存数据。

(在块[private performBlock:^ 中使用的正确上下文也是private 上下文)

【讨论】:

其实是第二种情况。生成大量实体,带有关系,然后显示在表格中。

以上是关于使用 NSPersistentContainer 实现核心数据并发的主要内容,如果未能解决你的问题,请参考以下文章

NSPersistentContainer 不创建数据库文件

NSPersistentContainer / 核心数据 / 只读存储

如何处理 NSPersistentContainer.loadPersistentStores 中的错误?

NSPersistentContainer, performBackgroundTask, 调用 perform 啥都不做

CoreData多个NSPersistentContainer实例导致Multiple NSEntityDescriptions +entity unable disambiguate的解决

NSPersistentContainer的loadPersistentStores的completionHandler是不是同步运行?