核心数据随机崩溃,可能存在并发问题
Posted
技术标签:
【中文标题】核心数据随机崩溃,可能存在并发问题【英文标题】:Random crash with core data, possible concurrency issue 【发布时间】:2016-10-19 07:54:13 【问题描述】:我有一段代码,它首先清空一个核心数据表,然后用新的和更新的数据填充它。此代码位于 DispatchQueue.main.async
块内,该块在异步请求完成后发生。这是函数中的相关代码。
这是我的代码:
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)
由于某种原因,我不时在 addOperation 代码块上发生随机崩溃。在最近的崩溃中,异常断点已被触发:
try self.managedObjectContext.save()
如果我点击继续,它会再次落在这个断点上,然后当我再次点击继续时,它会崩溃并显示程序集和这个错误:
*** 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
过去,我也看到它崩溃并出现以下错误: “尝试递归调用 -save: 在上下文中止”。
有什么想法吗?我将这些东西包装到 NSOperation 块中的全部原因是为了防止这种情况发生。显然那没有用。这是零星的,所以我不确定它是否已解决。
我猜发生了什么,当它尝试写入数据时,它仍在删除数据的过程中。
【问题讨论】:
看起来你的一个对象是 nil,你在检查吗? 可以使用苹果提供的并发队列。 developer.apple.com/library/content/documentation/Cocoa/… 【参考方案1】:您没有正确执行 Core Data 并发。正确的方法是在NSManagedObjectContext
上使用perform
和performAndWait
方法。像您的代码那样在操作队列中使用上下文是并发相关错误的秘诀。
调度队列在这里对您没有帮助。你可以仍然使用调度队列,但你还必须使用 Core Data 的并发方法来避免问题。
【讨论】:
啊。例如,在addOperation
块上(我将删除 NSOperations 的东西),我是将整个 for
循环包装在 performBlockAndWait
中,还是只是 try catch?
在这两种情况下,我基本上都将块操作定义行换成了self.managedObjectContext.performAndWait
。这似乎有效。类似于performAndWait
,我注意到managedObjectContext
上有一个perform
。为什么要使用perform
?为什么不按照我上面的做法写出来。
“执行”方法需要以任何方式包装与核心数据相关的所有内容。如果您可以在 Core Data 在自己的队列中完成工作时继续做其他工作,您会使用 perform
。
啊,有道理。通过包装所有涉及核心数据的东西,这包括NSEntityDescription.insertNewObject(forEntityName: "Track", into: self.managedObjectContext) as! Track
对吗?以上是关于核心数据随机崩溃,可能存在并发问题的主要内容,如果未能解决你的问题,请参考以下文章