I am using a database with NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
Everything works fine, I save objects, read, and delete without problems.
If set "-com.apple.CoreData.ConcurrencyDebug 1" :
- I save the object through the PerformAndWait block - ok
- I do fetch - receive an object, but its properties are empty (data = fault) and it crashes. (EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0))
sample code:
public final class DatabaseCore {
private let persistentContainer: NSPersistentContainer
private var backgroundContext: NSManagedObjectContext!
private let queue: DispatchQueue
public init() {
self.persistentContainer = Self.createPersistentContainer()
self.queue = queue
self.queue.async {
self.backgroundContext = Self.createNewBackgroundContext(container: self.persistentContainer)
}
// Private
private static func createPersistentContainer() -> NSPersistentContainer {
let model = NSManagedObjectModel(contentsOf: Bundle.module.url(forResource: "TestModel", withExtension: "momd")!)
let container = NSPersistentContainer(name: "TestModel", managedObjectModel: model)
let description = NSPersistentStoreDescription()
description.url = URL(fileURLWithPath: "/dev/null")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// print error
}
})
return container
}
private static func createNewBackgroundContext(container: NSPersistentContainer) -> NSManagedObjectContext {
let context = container.newBackgroundContext()
context.mergePolicy = NSOverwriteMergePolicy
context.undoManager = nil
return context
}
private static func saveContext(_ context: NSManagedObjectContext) {
context.performAndWait {
if !context.hasChanges { return }
do {
try context.save()
} catch {
// print error
}
}
}
// Public
public func upsert(_ block: @escaping (NSManagedObjectContext) -> Void, completion: (() -> Void)?) {
self.queue.async {
let context: NSManagedObjectContext! = self.backgroundContext
self.backgroundContext.performAndWait {
block(context)
Self.saveContext(context)
}
completion?()
}
}
public func fetch<ResultType: NSFetchRequestResult>(_ request: NSFetchRequest<ResultType>, completion: @escaping ([ResultType]) -> Void) {
self.queue.async {
var result: [ResultType] = []
self.backgroundContext.performAndWait {
do {
result = try request.execute()
} catch let error {
// print error
}
}
completion(result)
}
}
}
I set a breakpoint to result fetch func
if set "-com.apple.CoreData.ConcurrencyDebug 1":
(lldb) po record
<Test: 0x7b1400030070> (entity: Test; id: 0xbb200e8d680f1045 <x-coredata://1BFC3A95-3F7D-4A23-AD20-FDF23B575D73/CDLog/p1>; data: <fault>)
(lldb) po record.value
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been returned to the state before expression evaluation.
Without "-com.apple.CoreData.ConcurrencyDebug 1", everything works correctly, without a crash.
(lldb) po record
<Test: 0x7b1400028c80> (entity: Test; id: 0xb29880bd32a57757 <x-coredata://1BFC3A95-3F7D-4A23-AD20-FDF23B575D73/CDLog/p1>; data: <fault>)
(lldb) po record.value
0
How can this be fixed? Thank you! =)
Xcode 13.3