核心数据并发调试
Posted
技术标签:
【中文标题】核心数据并发调试【英文标题】:Core Data Concurrency Debugging 【发布时间】:2017-04-05 21:11:51 【问题描述】:这是我的 CoreDataStack 文件。当我通过并发调试运行项目时,我的应用程序在添加 pin 后立即崩溃。我认为这是因为我尝试在与创建上下文的线程不同的线程中访问数据。为了解决这个问题,我需要所有数据访问都发生在与创建上下文的线程相同的线程中。我做错了什么?
Run project with -com.apple.CoreData.ConcurrencyDebug 1
import CoreData
struct CoreDataStack
// MARK: - Properties
private let model: NSManagedObjectModel
internal let coordinator: NSPersistentStoreCoordinator
private let modelURL: URL
internal let dbURL: URL
internal let persistingContext: NSManagedObjectContext
internal let backgroundContext: NSManagedObjectContext
let context: NSManagedObjectContext
// MARK: - Initializers
init?(modelName: String)
// Assumes the model is in the main bundle
guard let modelURL = Bundle.main.url(forResource: modelName, withExtension: "momd") else
print("Unable to find \(modelName)in the main bundle")
return nil
self.modelURL = modelURL
// Try to create the model from the URL
guard let model = NSManagedObjectModel(contentsOf: modelURL) else
print("unable to create a model from \(modelURL)")
return nil
self.model = model
// Create the store coordinator
coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
// Create a persistingContext (private queue) and a child one (main queue)
// create a context and add connect it to the coordinator
persistingContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
persistingContext.persistentStoreCoordinator = coordinator
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.parent = persistingContext
// Create a background context child of main context
backgroundContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
backgroundContext.parent = context
// Add a SQLite store located in the documents folder
let fm = FileManager.default
guard let docUrl = fm.urls(for: .documentDirectory, in: .userDomainMask).first else
print("Unable to reach the documents folder")
return nil
self.dbURL = docUrl.appendingPathComponent("model.sqlite")
// Options for migration
let options = [NSInferMappingModelAutomaticallyOption: true,NSMigratePersistentStoresAutomaticallyOption: true]
do
try addStoreCoordinator(NSSQLiteStoreType, configuration: nil, storeURL: dbURL, options: options as [NSObject : AnyObject]?)
catch
print("unable to add store at \(dbURL)")
// MARK: - Utils
func addStoreCoordinator(_ storeType: String, configuration: String?, storeURL: URL, options : [NSObject:AnyObject]?) throws
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: dbURL, options: nil)
// MARK: - CoreDataStack (Removing Data)
internal extension CoreDataStack
func dropAllData() throws
// delete all the objects in the db. This won't delete the files, it will
// just leave empty tables.
try coordinator.destroyPersistentStore(at: dbURL, ofType: NSSQLiteStoreType , options: nil)
try addStoreCoordinator(NSSQLiteStoreType, configuration: nil, storeURL: dbURL, options: nil)
// MARK: - CoreDataStack (Batch Processing in the Background)
extension CoreDataStack
typealias Batch = (_ workerContext: NSManagedObjectContext) -> ()
func performBackgroundBatchOperation(_ batch: @escaping Batch)
backgroundContext.perform()
batch(self.backgroundContext)
// Save it to the parent context, so normal saving
// can work
do
try self.backgroundContext.save()
catch
fatalError("Error while saving backgroundContext: \(error)")
// MARK: - CoreDataStack (Save Data)
extension CoreDataStack
func save()
context.performAndWait()
if self.context.hasChanges
do
try self.context.save()
catch
fatalError("Error while saving main context: \(error)")
self.persistingContext.perform()
do
try self.persistingContext.save()
catch
fatalError("Error while saving persisting context: \(error)")
func autoSave(_ delayInSeconds : Int)
if delayInSeconds > 0
do
try self.context.save()
print("Autosaving")
catch
print("Error while autosaving")
let delayInNanoSeconds = UInt64(delayInSeconds) * NSEC_PER_SEC
let time = DispatchTime.now() + Double(Int64(delayInNanoSeconds)) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: time)
self.autoSave(delayInSeconds)
【问题讨论】:
【参考方案1】:确保在主线程中进行所有 UI 更改。
【讨论】:
谢谢!我删除添加注释到主线程,它的工作原理!以上是关于核心数据并发调试的主要内容,如果未能解决你的问题,请参考以下文章