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!")
}
}
}
我有以下核心数据单例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!")
}
}
}