Coredata - 多线程的最佳方式

时间:2017-04-11 14:21:05

标签: ios multithreading core-data

Parent_Context

Child_context(将Parent_Context设置为父级)

在后台使用的Child_context,用于添加新数据或更新现有数据。 Parent_Context在UI上显示并保存数据持久存储。

Child_context保存不应花费时间,因为更改仅在内存中更新。这更新为Parent_Context。

在写入商店时,Parent_Context保存可能需要一些时间。因此,我们可以根据应用程序的需要选择何时保存Parent_Context。

这就是我在多线程环境中需要时通常使用上下文的方法,或者在仍然在后台访问数据时更新UI。

// Parent or main
_mainQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_mainQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator;

// Child or background context
_privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_privateQueueContext setParentContext:self.mainQueueContext]; // Set main threads MOC as parent.

//To Save
    if ([self privateQueueContext].hasChanges) {
        [[self privateQueueContext] performBlockAndWait:^{
            NSError *childError = nil;
            if ([[self privateQueueContext] save:&childError]) {
                [[self mainQueueContext] performBlock:^{
                    NSError *parentError = nil;
                    if (![[self mainQueueContext] save:&parentError]) {
                        DLog(@"Error saving parent, error: %@", [parentError localizedDescription]);
                    }
                }];           
            } else {
                DLog(@"Error saving child, error: %@", [childError localizedDescription]);
            }
        }];
    }

如果有更好的方法来处理这种情况,请分享。感谢。

通过在后台线程中保存上下文,我看不到UI被冻结。发布问题以了解其他更好的方法并了解核心数据。

1 个答案:

答案 0 :(得分:3)

我更喜欢至少有2个上下文。

与持久性存储相关联的主要内容(没有父上下文)为privateQueueConcurrencyType,因此在保存到磁盘期间不会影响UI。

第二个是用于UI的viewContext,它是privateContext的子上下文。

我通常还有另一个用于后台导入的导入,它是UI上下文的子上下文,并配置为privateQueueConcurrencyType,因此它不会阻止UI。保存后,UI会更新,然后更改将保存到持久性存储中(以递归方式保存)。

此外,每当我要进行更改时,我都会为viewContext创建一次性子上下文。我在childContext中进行更改,然后以递归方式保存。我发现这种方式可以在多用户情况下多次保存我的屁股。

以下是我的设置:

lazy var privateSaveContext: NSManagedObjectContext = {
    let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    moc.name = "privateSaveContext"
    moc.persistentStoreCoordinator = self.coordinator
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    return moc
}()

lazy var viewContext: NSManagedObjectContext = {
    let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    moc.name = "viewContext"
    moc.parent = self.privateSaveContext
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    return moc
}()

lazy var importContext: NSManagedObjectContext = {
    let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    moc.name = "importContext"
    moc.parent = self.viewContext
    moc.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    return moc
}()

保存到磁盘时,我以递归方式保存:

class func save(_ moc: NSManagedObjectContext) {
    moc.performAndWait {
        if moc.hasChanges {
            DLog("Inserted objects count = \(moc.insertedObjects.count)")
            do {
                try moc.save()
                if moc.parent == nil { DLog("SAVED changes to persistent store") }
                DLog("SAVED context '\(moc)'")
            } catch {
                DLog("ERROR saving context '\(moc)' - \(error)")
            }
        } else {
            if moc.parent == nil { DLog("SKIPPED saving changes to persistent store, because there are no changes") }
            DLog("SKIPPED saving context '\(moc)' because there are no changes")
        }
        if let parentContext = moc.parent {
            save(parentContext)
        }
    }
}

P.S。 DLog是我使用的,它打印出函数名称,日期,时间等。您只需将其更改为print