Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift CoreData: error: Serious application error. Exception was caught during Core Data change processing.

I am writing one program on iOS and very race I am facing this error:

2015-11-06 10:57:24.289 NETFNET[2503:976392] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null) 2015-11-06 10:57:24.293 NETFNET[2503:976392] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'

I am trying to access Data Base simultaneously, I think, from main and background threads. I have seen a lot of solutions for Objective C, but none for Swift (I don't know Objective C...). Unfortunately, I don't know how to work with Grand Central Dispatch and, in fact, my program does not really need several treads (I mean it need it, but if some thread loses info from one function for one time, nothing bad will happen). I just want to have stable program on Swift 1 or 2, so I will be thankful for any help.

like image 302
Alex Avatar asked Nov 06 '15 08:11

Alex


3 Answers

You need to create a private NSManagedObjectContext with private queue concurrency type and use it to access CoreData whenever operating on a background thread.

So suppose I need to run a database operation on the background, I can dispatch that work to the background thread as

dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
        //call your background operation.
    })

Then in the background operation I can create a private NSManagedObjectContext as

let moc = … //Our primary context on the main queue

let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc

privateMOC.performBlock {
    //operations
    do {
        try privateMOC.save()
    } catch {
        fatalError("Failure to save context: \(error)")
    }
}

Read through Apple's CoreData Concurrency Guide to get a good understanding before implementing core data operations on multiple threads.

like image 81
mohonish Avatar answered Oct 20 '22 23:10

mohonish


Very good. I tried it, it worked fine for me. Thank you very much.

Previous Code:

        do {
            try CDHelper.shared.context.save()
        }
        catch let error as NSError {
            // Error mesajlarını ekle!!
            print("Could not fetch \(error), \(error.localizedDescription)")
            print("Could not fetch \(error), \(error.localizedFailureReason)")
        }


// MARK: - CONTEXT
lazy var context: NSManagedObjectContext = {
    let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
    moc.persistentStoreCoordinator = self.coordinator
    return moc
}()

// MARK: - MODEL
lazy var model: NSManagedObjectModel = {
    return NSManagedObjectModel(contentsOfURL:self.modelURL)!
}()

// MARK: - COORDINATOR
lazy var coordinator: NSPersistentStoreCoordinator = {
    return NSPersistentStoreCoordinator(managedObjectModel:self.model)
}()

lazy var modelURL: NSURL = {
    let bundle = NSBundle.mainBundle()
    if let url = bundle.URLForResource("Model", withExtension: "momd") {
        return url
    }
    print("CRITICAL - Managed Object Model file not found")
    abort()
}()

you should change the code this way:

let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc

privateMOC.performBlock({
    do {
        try privateMOC.save()
    } catch {
        fatalError("Failure to save context: \(error)")
    }
})
like image 40
Yunus T. Avatar answered Oct 20 '22 22:10

Yunus T.


Just calling your CoreData Function inside

DispatchQueue.main.async {

...

}

worked for me

like image 22
Tobias Krainhöfner Avatar answered Oct 20 '22 21:10

Tobias Krainhöfner