如何在正确的队列上初始化ManagedObjectContext? [英] How to init ManagedObjectContext on the right queue?

查看:216
本文介绍了如何在正确的队列上初始化ManagedObjectContext?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

非常需要一个建议,目前用尽了所有建议.我堆满了与核心数据并发相关的问题,要调试,请使用-"com.apple.CoreData.ConcurrencyDebug"和我所拥有的:

Extremely need an advice, currently run out of ideas. I stack with core data concurrency related issue, to debug I use -"com.apple.CoreData.ConcurrencyDebug" and what I have:

堆栈:

线程3队列:coredata(serial)

Thread 3 Queue: coredata(serial)

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

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

1-[NSManagedObjectContext executeFetchRequest:error:]:

1 -[NSManagedObjectContext executeFetchRequest:error:]:

2个NSManagedObjectContext.fetch(__ObjC.NSFetchRequest)引发-> Swift.Array:

2 NSManagedObjectContext.fetch (__ObjC.NSFetchRequest) throws -> Swift.Array:

3 AppDelegate.(fetchRequest NSFetchRequest)-> [A]).(关闭#1)

3 AppDelegate.(fetchRequest NSFetchRequest) -> [A]).(closure #1)

我从这里进入AppDelegate :: fetchRequest:

I get into AppDelegate::fetchRequest from here:

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

我在串行队列(self.queueContainer)上执行所有coredata内容.

I perform all coredata stuff on the serial queue(self.queueContainer).

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;
}

这是我发现有用的东西.

This is what I found useful.

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

Below are some of the rules that must be followed if you do not want your app that uses CoreData to crash (or) corrupt the database:

NSManagedObjectContext应该仅在与其关联的队列上使用.

A NSManagedObjectContext should be used only on the queue that is associated with it.

如果使用.PrivateQueueConcurrencyType初始化,则会创建一个与该对象关联的内部专用队列.可以通过实例方法.performBlockAndWait(用于同步操作)和.performBlock(用于异步操作)访问此队列

If initialized with .PrivateQueueConcurrencyType, a private, internal queue is created that is associated with the object. This queue can be accessed by instance methods .performBlockAndWait (for sync ops) and .performBlock (for async ops)

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

If initialized with .MainQueueConcurrencyType, the object can be used only on the main queue. The same instance methods ( performBlock and performBlockAndQueue) can be used here as well. An NSManagedObject should not be used outside the thread in which it is initialized

现在我正在四处搜寻,但说实话不能确定我的托管对象上下文(MOC)是否与正确的队列相关联.

Now I'm digging around but honestly speaking can't be sure that my managed object context(MOC) is associated with the right queue.

摘自手册:

...这样的结果是,上下文假定默认的所有者是为其分配线程的线程或队列,这是由调用其init方法的线程确定的.

...A consequence of this is that a context assumes the default owner is the thread or queue that allocated it—this is determined by the thread that calls its init method.

在AppDelegate中,我不直接使用MOC进行操作,而是实例化拥有此MOC的NSPersistentContainer.以防万一我也在同一个串行队列上执行此操作.

In the AppDelegate I do not operate with MOC directly, instead of this I instantiating NSPersistentContainer which owns this MOC. Just in case I'm doing this on the same serial queue as well.

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是什么?

I am not a Swift coder , but What is queueContainer?

您应该不要自己做线程,您应该使用NSManagedObjectContext

You should not do the threading yourself, you should use the NSManagedObjectContext block methods as you wrote in your quotation:

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

The same instance methods ( performBlock and performBlockAndQueue) can be used here as well.

managedObjectContext.performBlock {

无论使用什么managedObjectContext,都应使用该上下文块方法,并在这些块方法中进行操作.

Whatever managedObjectContext you are using, you should use that context block method and do your stuff inside the block methods.

在此处查看文档有关如何正确执行此操作的示例.

Look at the documentation here for examples on how to do this correctly.

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

Also to avoid crashes and threading errors:

NSManagedObject实例不能在两个实例之间传递 队列.这样做会导致数据损坏和终止 的应用程序.何时需要移交托管对象 从一个队列到另一个队列的引用,必须通过 NSManagedObjectID实例.

NSManagedObject instances are not intended to be passed between queues. Doing so can result in corruption of the data and termination of the application. When it is necessary to hand off a managed object reference from one queue to another, it must be done through NSManagedObjectID instances.

您可以通过调用 NSManagedObject实例上的objectID方法.

You retrieve the managed object ID of a managed object by calling the objectID method on the NSManagedObject instance.

这篇关于如何在正确的队列上初始化ManagedObjectContext?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆