coredata更新json后台线程问题

coredata update json background thread problem

我有以下核心数据单例class 在我的 appdelegate 中,我尝试从 json 更新数据 但是在我的应用程序启动时,我收到有关线程的不同错误消息 喜欢

Main Thread Checker: UI API called or observer of NSManagedObjectContextObjectsDidChangeNotification or Incorrect guard value

问题是什么?我应该做哪些更改才能使其正常工作? 谢谢

import CoreData
import Foundation
class CoreDataStack {
   
  static let sharedManager = CoreDataStack()
  private init() {} // Prevent clients from creating another instance.
   
  //This is the name of your coreData Database
  static let modelName = "myDB"
  static let FirstLaunchKey = "firstLaunch"
 
  lazy var managedObjectModel: NSManagedObjectModel = {
    let modelURL = Bundle.main.url(forResource: CoreDataStack.modelName, withExtension: "momd")!
    return NSManagedObjectModel(contentsOf: modelURL)!
  }()
   
   
  lazy var applicationDocumentsDirectory: URL = {
    return NSPersistentContainer.defaultDirectoryURL()
  }()
   
  lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
     
    let persistentStoreURL = self.applicationDocumentsDirectory.appendingPathComponent(CoreDataStack.modelName + ".sqlite")
     
    do {
       
      // let dict = [NSSQLitePragmasOption: ["journal_mode":"DELETE"]]
  try coordinator.addPersistentStore(ofType: NSSQLiteStoreType,
                    configurationName: nil,
                    at: persistentStoreURL,
              options: [NSMigratePersistentStoresAutomaticallyOption: true,
                   NSInferMappingModelAutomaticallyOption: false])
    } catch {
      fatalError("Persistent store error! \(error)")
    }
     
    return coordinator
  }()
   
   
  fileprivate lazy var saveManagedObjectContext: NSManagedObjectContext = {
    let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
    moc.persistentStoreCoordinator = self.persistentStoreCoordinator
    return moc
  }()
   
  @objc lazy var mainObjectContext: NSManagedObjectContext = {
    let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    managedObjectContext.parent = self.saveManagedObjectContext
    return managedObjectContext
  }()
   
  func saveMainContext() {
    guard mainObjectContext.hasChanges || saveManagedObjectContext.hasChanges else {
      return
    }
 
    mainObjectContext.performAndWait() {
      // print("save performAndWait")
      do {
        try self.mainObjectContext.save()
      } catch {
        fatalError("Error saving main managed object context! \(error)")
      }
    }
    saveManagedObjectContext.perform() {
      // print("save simple")
      do {
        try self.saveManagedObjectContext.save()
      } catch {
        fatalError("Error saving private managed object context! \(error)")
      }
    }
  }
  func removeDatabaseForVersion(version:String){
    let previouslyVersion = UserDefaults.standard.bool(forKey: version)
     if !previouslyVersion {
      UserDefaults.standard.set(true, forKey: version)
      // Default directory where the CoreDataStack will store its files
      let directory = NSPersistentContainer.defaultDirectoryURL()
      let url = directory.appendingPathComponent(CoreDataStack.modelName + ".sqlite")
       
      let shmURL = directory.appendingPathComponent(CoreDataStack.modelName + ".sqlite-shm")
       
      let walURL = directory.appendingPathComponent(CoreDataStack.modelName + ".sqlite-wal")
       
      _ = try? FileManager.default.removeItem(at: url)
      _ = try? FileManager.default.removeItem(at: shmURL)
      _ = try? FileManager.default.removeItem(at: walURL)
    }
  }
   
}

在我的 appdelegate 中:

UpdateDbClass.updateDatabase(entityName: DbTable.VehiclesEntity.rawValue, completionHandler: {
      print(" DB updated delegate")
    })

在更新中 class:

import UIKit
import Alamofire
import CoreData


enum LoaderError:String{
    case
    JsonFailed,
    PathFailed,
    NoEntityDescription,
    UnknownError
}

enum DbTable:String{
    case
    VehiclesEntity,
    PhotosEntity,
    ModelsEntity,
    NewsEntity,
    StylesEntity
}

class UpdateDbClass {
    
    
    static func updateDatabase(entityName:String,completionHandler: @escaping () -> Void){
      var url = URL(string: UrlRepository.VehiclesJsonUrl!)!
      
   
      var table = ""
          switch entityName {
          case DbTable.VehiclesEntity.rawValue:
              table = "Vehicles"
              url = URL(string: UrlRepository.VehiclesJsonUrl!)!
          case DbTable.PhotosEntity.rawValue:
              table = "Photos"
              url = URL(string: UrlRepository.PhotosJsonUrl!)!
               table = "Styles"
                url = Bundle.main.url(forResource: "Styles", withExtension: "json")!
                  // url = URL(string: UrlRepository.NewsJsonUrl!)!
          default:
              break
          }
          let uuid = UUID().uuidString
          let parameters: Parameters = [
              "id": uuid
          ]

     let queue = DispatchQueue(label: "com.my.test", qos: .background, attributes: .concurrent)
    

      AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding(destination: .queryString), headers: nil).responseJSON(queue:queue){ response in
              switch response.result {
              case let .success(value):
                  if let items = value as? [[String: Any]] {

                      var itemsArray:[Int32] = []
                      for item in items{
                          if let id = item["id"] as? Int32{
                               itemsArray.append(id)
                          }
                      }

                      guard let entity = NSEntityDescription.entity(forEntityName: table, in:(CoreDataStack.sharedManager.mainObjectContext)) else {
                          fatalError("Could not find entity descriptions!")
                      }

              switch entityName {

                  case DbTable.StylesEntity.rawValue: //Styles
                      checkDeletedRecords(jsonItems: itemsArray,table: table)

                      for item in items{
                          guard let id = item["id"] as? Int32 else {return}
                          //Check if not exists
                          if  !CheckIfExists(id: id,table:table){
                             print("id \(id) does not exist")
                              //Insert Record
                              let object = Styles(entity: entity, insertInto: CoreDataStack.sharedManager.mainObjectContext)
                      object.setValue(item["id"], forKey: "id")
                      object.setValue(item["style"] as! String, forKey: "style")
                      object.setValue(item["image"] as! String, forKey: "image")
         
                      CoreDataStack.sharedManager.saveMainContext()
                          }
                          else{    //Update Record
                             // print("id \(item["id"]) exists")

                              do{
                                  let fetchRequest = NSFetchRequest<Styles>(entityName:"Styles")
                                  let predicate = NSPredicate(format: "id == %d",item["id"] as! Int32)
                                  fetchRequest.predicate = predicate
                                  let req =  try CoreDataStack.sharedManager.mainObjectContext.fetch(fetchRequest)
                                  let object = req[0] as NSManagedObject
                                object.setValue(item["style"] as! String, forKey: "style")
                                 object.setValue(item["image"] as! String, forKey: "image")
                                

                                   CoreDataStack.sharedManager.saveMainContext()

                              }catch{
                                  print("there was an error")
                              }
                              completionHandler()
                          }
                      }
                      break;

             
                      default:
                          break
                      }
                   }
                  break
              case let .failure(error):
                  print(error as NSError)
                  break
              }
          }
      

       }
      


  
}

protocol CoreDataWorkerProtocol {
    associatedtype EntityType
}

enum VoidResult {
    case success
    case failure(NSError)
}

响应 json 在后台线程中调用,您正尝试在后台线程中使用 viewContext

如果你想在后台使用 viewContext,你应该使用 perform 块。

比如像这样

  AF.request(:).responseJSON(queue:queue){ response in
       let mainContext = CoreDataStack.sharedManager.mainObjectContext
        mainContext.perform { 
        guard let entity = NSEntityDescription.entity(forEntityName: table, in: mainContext) else {
                fatalError("Could not find entity descriptions!")
            }    
        }
   }