如何在右侧队列上初始化ManagedObjectContext?

非常需要一个build议,目前用完了想法。 我堆栈与核心数据并发相关的问题,debugging我使用 – “com.apple.CoreData.ConcurrencyDebug”和我有:

堆栈:

线程3队列:coredata(serial)

0 + [NSManagedObjectContext Multithreading_Violation_AllThatIsLeftToUsIsHonor ]:CoreData`- [NSManagedObjectContext executeFetchRequest:error:]:

1 – [NSManagedObjectContext executeFetchRequest:error:]:

2 NSManagedObjectContext.fetch(__ObjC.NSFetchRequest)抛出 – > Swift.Array:

3(AppRelegate。)(fetchRequest NSFetchRequest) – > [A])。(closure#1)

我从这里进入AppDelegate :: fetchRequest:

let messageRequest: NSFetchRequest<ZMessage> = ZMessage.fetchRequest(); messageRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: false)]; let messageArray: Array<ZMessage> = self.fetchRequest(messageRequest); 

我在串行队列(self.queueContainer)上执行所有coredata的东西。

 public func fetchRequest<T>(_ request: NSFetchRequest<T>) -> Array<T> { var retval: Array<T> = Array<T>(); self.queueContainer.sync { do { retval = try self.persistentContainer.viewContext.fetch(request); } catch { let nserror = error as NSError; fatalError("[CoreData] Unresolved fetch error \(nserror), \(nserror.userInfo)"); } } return retval; } 

这是我觉得有用的。

以下是一些必须遵守的规则,如果您不希望使用CoreData的应用程序崩溃(或)损坏数据库:

一个NSManagedObjectContext应该只用于与之关联的队列。

如果使用.PrivateQueueConcurrencyType进行初始化,则会创build一个与该对象关联的私有内部队列。 此队列可以通过实例方法.performBlockAndWait(用于同步操作)和.performBlock(用于asynchronous操作)

如果使用.MainQueueConcurrencyType进行初始化,则只能在主队列上使用该对象。 这里也可以使用相同的实例方法(performBlock和performBlockAndQueue)。 一个NSManagedObject不应该在它初始化的线程之外使用

现在我正在挖掘,但说实话,不能确定我的托pipe对象上下文(MOC)与正确的队列相关联。

从手册:

…这样做的后果是,上下文假定默认所有者是分配它的线程或队列 – 这是由调用其init方法的线程决定的。

在AppDelegate中,我不直接操作MOC,而是实例化拥有这个MOC的NSPersistentContainer。 以防万一我在同一个串行队列上这样做。

 public lazy var persistentContainer: NSPersistentContainer = { self.queueContainer.sync { let container = NSPersistentContainer(name: "Joker") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container } }() 

提前致谢。

我不是一个Swift编码器,但什么是queueContainer?

你不应该自己做线程 ,你应该使用你在引用中写的NSManagedObjectContext 块方法 :

这里也可以使用相同的实例方法(performBlock和performBlockAndQueue)。

 managedObjectContext.performBlock { 

无论您使用的是什么managedObjectContext,您都应该使用该上下文块方法,并在块方法中执行您的操作。

查看这里的文档 ,了解如何正确执行此操作的示例。

还要避免崩溃和线程错误:

NSManagedObject实例不打算在队列之间传递。 这样做可能会导致数据损坏并终止应用程序。 当需要将pipe理对象引用从一个队列转移到另一个队列时,必须通过NSManagedObjectID实例完成。

通过调用NSManagedObject实例上的objectID方法来检索托pipe对象的托pipe对象标识。