coredata更新json后台线程问题
Posted
技术标签:
【中文标题】coredata更新json后台线程问题【英文标题】:coredata update json background thread problem 【发布时间】:2020-10-08 16:48:58 【问题描述】:我有以下 coredata 单例类 在我的 appdelegate 中,我尝试从 json 更新数据 但是在我的应用程序启动时,我收到有关线程的不同错误消息 喜欢
主线程检查器:调用 UI API 或 NSManagedObjectContextObjectsDidChangeNotification 的观察者 或不正确的保护值
有什么问题,我应该做些什么改变才能让它工作? 谢谢
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")
)
在更新的b类中:
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)
【问题讨论】:
错误信息提到了NSManagedObjectContextObjectsDidChangeNotification
的观察者。你有任何观察这个通知的代码吗?如果是这样,观察代码会发生什么?
不,我没有观察者!
我现在收到此错误:主线程检查器:在后台线程上调用 UI API:-[UIViewController childViewControllers] PID:2441,TID:136254,线程名称:
【参考方案1】:
响应 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!")
【讨论】:
以上是关于coredata更新json后台线程问题的主要内容,如果未能解决你的问题,请参考以下文章