核心数据随机崩溃,可能并发问题



我有一段代码,它首先清空Core Data表,然后用新的和更新的数据填充它。该代码位于一个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块的全部原因是为了防止这个。显然这行不通。这是零星的,所以我不确定它是否被解决了。

我猜发生的事情是,它仍然在删除数据的过程中,当它试图写数据

你没有正确地做Core Data并发。正确的方法是在NSManagedObjectContext上使用performperformAndWait方法。像你的代码那样在操作队列中使用上下文会导致并发相关的bug。

调度队列在这里没有帮助。仍然可以使用分派队列,但是必须使用Core Data的并发方法来避免问题。

最新更新