我已阅读以下内容PerformBlock: 和 PerformBlockAndWait: 之间的行为差异? https://stackoverflow.com/questions/32198678/behavior-differences-between-performblock-and-performblockandwait但无法找到我的问题的答案。
以下代码摘自 RayWenderlichvideo https://www.youtube.com/watch?v=lMT96wUsjMQ。具体在10:05 https://youtu.be/lMT96wUsjMQ?t=605代码是某物像这样:
class CoreDataStack {
var coordinator : NSPersistentStoreCoordinator
init(coordinator: NSPersistentStoreCoordinator){
self.coordinator = coordinator
}
// private, parent, in background used for saving
private lazy var savingContext : NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
moc.persistentStoreCoordinator = coordinator
return moc
}()
lazy var mainManagedObjectedContext : NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
moc.parent = self.savingContext
return moc
}()
func saveMainContext() {
guard savingContext.hasChanges || mainManagedObjectedContext.hasChanges else {
return
}
mainManagedObjectedContext.performAndWait {
do {
try mainManagedObjectedContext.save()
}catch let error{
fatalError(error.localizedDescription)
}
}
savingContext.perform {
do {
try self.savingContext.save()
}catch let error{
fatalError(error.localizedDescription)
}
}
}
}
据我了解,发生的情况是主上下文只是将更改传递给其父上下文,这是一个私有的后台上下文。它同步执行此操作。
然后父级私有上下文在后台线程中对 sqlite 进行实际保存异步地。长话短说,这对我们的性能有很大帮助。但数据完整性又如何呢?
想象一下如果我要这样做:
let coredataManager = CoreDataStack()
coredataManager.saveMainContext() // save is done asynchronously in background queue
coredataManager.mainManagedObjectedContext.fetch(fetchrequest)
如何保证我的提取正在读取最新和更新的结果?
如果我们异步写入,那么同时进行的另一次读取是否有可能会产生意外结果,即保存更改的结果可能存在或不存在?
EDIT:我用下面的代码进行了改进。我可以让我的保存接受一个completionHandler 参数。但这并不能解决整个问题。如果我从其他地方的 mainQueue 发出 fetchRequest,但不知道同时发生了保存,该怎么办?
enum SaveStatus{
case noChanges
case failure
case success
}
func saveMainContext(completionHandler: (SaveStatus -> ())) {
guard savingContext.hasChanges || mainManagedObjectedContext.hasChanges else {
completionHandler(.noChanges)
return
}
mainManagedObjectedContext.performAndWait {
do {
try mainManagedObjectedContext.save()
}catch let error{
completionHandler(.failure)
fatalError(error.localizedDescription)
}
}
savingContext.perform {
do {
try self.savingContext.save()
completionHandler(.succes)
}catch let error{
completionHandler(.failure)
fatalError(error.localizedDescription)
}
}
}