简体   繁体   中英

Random crash with core data, possible concurrency issue

I have a section of code where it firstly empties out a Core Data table, then fills it back up with new and updated data. This code is inside a DispatchQueue.main.async block, that occurs after an asynchronous request has been completed. This is the relevant code from the function.

Here is my code:

let queue = OperationQueue()
let deleteOperation = BlockOperation {
    let fetchRequest = Track.fetchRequest()

    let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
    batchDeleteRequest.resultType = .resultTypeCount

    do {
        try self.managedObjectContext.execute(batchDeleteRequest)
        self.managedObjectContext.reset()
    }
    catch {
        fatalCoreDataError(error)
        self.debug.log(tag: "RecentSessionsViewController", content: "Failed to delete cache")
        return
    }
}

let addOperation = BlockOperation {
    for track in tempTracks {
        let masterListEntry = NSEntityDescription.insertNewObject(forEntityName: "Track", into: self.managedObjectContext) as! Track

        masterListEntry.id = track["id"] as! NSNumber
        masterListEntry.name = track["name"] as! String
        masterListEntry.comment = track["comment"] as! String

        do {
            try self.managedObjectContext.save()

            self.trackMasterList.append(masterListEntry)
        }
        catch {
            self.debug.log(tag: "RecentSessionsViewController", content: "Core data failed")
            fatalError("Error: \(error)")
        }
    }
}

addOperation.addDependency(deleteOperation)
queue.addOperations([deleteOperation, addOperation], waitUntilFinished: false)

I have random crashes from time to time on the addOperation block of code for some reason. In the most recent crash, an exception breakpoint has been trigger on:

try self.managedObjectContext.save()

If I hit continue, it lands on this breakpoint again, then when I hit continue again, it crashes showing assembly and this error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010c70f34b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010bd5321e objc_exception_throw + 48
    2   CoreFoundation                      0x000000010c778265 +[NSException raise:format:] + 197
    3   CoreFoundation                      0x000000010c6a762b -[__NSCFSet addObject:] + 155
    4   CoreData                            0x000000010c2427ff -[NSManagedObjectContext(_NSInternalChangeProcessing) _processPendingUpdates:] + 399
    5   CoreData                            0x000000010c23cccd -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2445
    6   CoreData                            0x000000010c240e0c -[NSManagedObjectContext save:] + 412
    7   AppName                            0x000000010b0db7eb _TFFFFC8AppName28RecentSessionsViewController22refreshListFT_T_U_FTGSqV10Foundation4Data_GSqCSo11URLResponse_GSqPs5Error___T_U_FT_T_U0_FT_T_ + 6459
    8   AppName                            0x000000010b086987 _TTRXFo___XFdCb___ + 39
    9   Foundation                          0x000000010b8572cd __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
    10  Foundation                          0x000000010b856faf -[NSBlockOperation main] + 101
    11  Foundation                          0x000000010b8556ac -[__NSOperationInternal _start:] + 672
    12  Foundation                          0x000000010b8515ef __NSOQSchedule_f + 201
    13  libdispatch.dylib                   0x00000001134100cd _dispatch_client_callout + 8
    14  libdispatch.dylib                   0x00000001133ede6b _dispatch_queue_serial_drain + 236
    15  libdispatch.dylib                   0x00000001133eeb9f _dispatch_queue_invoke + 1073
    16  libdispatch.dylib                   0x00000001133f13b7 _dispatch_root_queue_drain + 720
    17  libdispatch.dylib                   0x00000001133f108b _dispatch_worker_thread3 + 123
    18  libsystem_pthread.dylib             0x00000001137bf746 _pthread_wqthread + 1299
    19  libsystem_pthread.dylib             0x00000001137bf221 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

In the past, I've also seen it crash with the following error: "attempt to recursively call -save: on the context aborted".

Any ideas what is going on? The whole reason I wrapped these things into NSOperation blocks was in an attempt to prevent this. Clearly that didn't work. This is sporadic, so I'm never sure if its been solved or not.

I'm guessing what is happening is that its still in the process of deleting data, when it tries to write data.

You're not doing Core Data concurrency correctly. The right way is to use the perform and performAndWait methods on NSManagedObjectContext . Using a context in an operation queue like your code does is a recipe for concurrency related bugs.

Dispatch queues don't help you here. You can still use dispatch queues, but you must also use Core Data's concurrency methods to avoid problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM