2017-04-05 34 views
0

这是我的CoreDataStack文件。当我在添加一个引脚后立即运行带有并发性的项目时,我的应用程序崩溃。我认为这会导致我尝试访问与创建上下文的线程不同的线程中的数据。为了解决这个问题,我需要所有的数据访问都在与创建它的上下文的线程相同的线程中进行。我做错了什么?核心数据并发调试

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

确保您在主线程中的所有用户界面的变化。

+0

谢谢!我删除添加注释到主线程,它的工作原理! –