Unexpected Core Data Multithreading Violation

可紊 提交于 2021-02-18 20:40:36

问题


I'm using Apple's concurrency core data debugger.

-com.apple.CoreData.ConcurrencyDebug 1

From time to time I got __Multithreading_Violation_AllThatIsLeftToUsIsHonor__, even I'm almost sure threading is not violated.

This is part of code where exception occurs (code is part of protocol that extends NSManagedObject):

public static func find(arrayBy predicate: NSPredicate, sort: [NSSortDescriptor] = [], limit: Int? = nil) -> [Self] {
    let fetchRequest = NSFetchRequest<Self>(entityName: "\(Self.self)")
    fetchRequest.predicate = predicate
    fetchRequest.sortDescriptors = sort

    do {
        return try Context.current.fetch(fetchRequest) // Exception!!!
    } catch let error {
        Logger.fatal("Failed to perform fetch: \(error)")
        return []
    }
}

Code is executed within context's perform: block.

Here is thread information:

and debuger info to confirm that perform is executed on the right NSManagedContext:

(lldb) po Context.current
<StoreContext: 0x7f854b556610>

Entity name is extracted successfully:

po fetchRequest.entityName!
"Position"

Predicate is constructed of pure String objects (no managed objects used at all):

(lldb) po fetchRequest.predicate!
ANY employees.company.id == "282372"

Sort descriptors are not used at all in this case:

po fetchRequest.sortDescriptors!
0 elements

Limit is completely ignored.

What am I missing? Does anyone has any idea what can be wrong here?

Edit:

To clarify, Context.current is set just before dispatching the block:

Context.current = managedObjectContext
managedObjectContext.performAndWait {
   //...
}

You can see on the screenshot that Thread 13 is running on Queue: NSManagedObject 0x7f854b556610 (serial). Also, when exception occurs Context.current returns <StoreContext: 0x7f854b556610>. By looking at the memory address it's easy to conclude block is executing on the right queue.


回答1:


Storing the "current" background context in a global state is a bad practice. I can't point out where exactly in your code it is messing up, but unexpected things can happen with global state when multithreading is involved. Change your find function to accept a context as a parameter. This will avoid using any global state and is will likely fix your problem.




回答2:


It is recommended to avoid using the .performAndWait API, to be used only at the rarest of the rare occasions, when everything else has failed!
Evaluate morphing Context.current to managedObjectContext.perform throughout the application.
The effect of this change would be addition of asynchronicity in all your database operations.
It may sound of a massive change to ask for but trust me, just decide to treat Core Data as a completely asynchronous API & life will be much better this way.
I'm sure the current crash you are facing is a result of compound result of the corrupted behavior of .performAndWait

This, this and this are some good reads on the topic.




回答3:


Check out this blog to get better understanding of multithreading in Core Data

https://cocoacasts.com/core-data-and-concurrency/

https://cocoacasts.com/more-core-data-and-concurrency/



来源:https://stackoverflow.com/questions/41999983/unexpected-core-data-multithreading-violation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!