我已经在我的应用中实现了核心数据。每隔30秒就会在后台执行一次API调用,以根据JSON响应更新数据库。因此,当我解析并尝试将JSON响应保存到我的Core数据中时,我想在后台执行它。它不应该影响我的用户界面。当前,当进行保存时,由于托管对象上下文操作是在主线程上执行的,因此它将阻止UI。我遵循this博客的方法。
有时会随机崩溃,并显示以下日志:
Fatal Exception: NSGenericException
*** Collection <__NSCFSet: 0x283e6a220> was mutated while being enumerated.
首先,我们有一个正确配置的CoreData堆栈:
container = NSPersistentContainer(name: "UserData")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (description, error) in
if let error = error as NSError? {
DataController.isInitialized = false
fatalError("Unresolved error \(error), \(error.userInfo)")
}
else {
DataController.isInitialized = true
}
})
mainContext = container.viewContext
mainContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
...
backgroundContext = container.newBackgroundContext()
backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
...
第二个是JSON数据请求(
static func request(performSave: Bool, name: String, completionHandler: @escaping (Bool, FooDataResponseResult, Error?) -> Void) {
var urlComponents = URLComponents()
...
var dataRequest = URLRequest(url: urlComponents.url!)
dataRequest.httpMethod = "GET"
let urlRequestCompletionHandler: (Data?, URLResponse?, Error?) -> Void = {
(data, response, error) in
guard let data = data, error == nil else {
// Eroror handling
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let decoder = JSONDecoder()
do {
let responseObject = try decoder.decode(FooDataResponse.self, from: data)
if responseObject.results.count>0 {
DispatchQueue.global(qos: .userInitiated).async {
completionHandler(performSave,responseObject.results[0],nil)
}
}
else {
// No data
}
}
} catch {
// Error
}
}
let task = URLSession.shared.dataTask(with: dataRequest, completionHandler: urlRequestCompletionHandler)
task.resume()
}
第三completionHandler
实现。 backgroundContext
在这里发挥作用:
let completionHandlerFooDataRequest: (Bool, FooDataResponseResult?, Error?) -> Void = {
...
let taskContext = AppDelegate.appDelegate.dataController.backgroundContext
taskContext.performAndWait {
// all fetches on the taskContext
// all managed Object creation on taskContext
// all insert on taskContext
// dont forget to save your changes
taskContext.save()
}
这仅概述了如何在后台完成JSON请求的处理,响应处理和核心数据更新。