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.