如何在不冻结UI的情况下在后台执行Core数据获取请求

问题描述 投票:0回答:1

我已经在我的应用中实现了核心数据。每隔30秒就会在后台执行一次API调用,以根据JSON响应更新数据库。因此,当我解析并尝试将JSON响应保存到我的Core数据中时,我想在后台执行它。它不应该影响我的用户界面。当前,当进行保存时,由于托管对象上下文操作是在主线程上执行的,因此它将阻止UI。我遵循this博客的方法。 enter image description here

有时会随机崩溃,并显示以下日志:

Fatal Exception: NSGenericException
*** Collection <__NSCFSet: 0x283e6a220> was mutated while being enumerated.
ios objective-c swift core-data nsmanagedobjectcontext
1个回答
0
投票

首先,我们有一个正确配置的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请求的处理,响应处理和核心数据更新。

© www.soinside.com 2019 - 2024. All rights reserved.