首页 > 解决方案 > Swift:核心数据的线程问题

问题描述

我有一个应用程序,我在其中调用端点以从 API 检索产品列表:

var productList = [Product]

private func retrieveProducts() {
    API.client.call(.products, expecting: [Product].self) { (result, products) in
        switch result {
        case .failure:
            print("Unable to retrieve products")
        case .success:
            guard let productResponse = products else { return }
            for product in productResponse {
                productList.append(product)
            }
        }
    }
}

注意:我们为 API 调用使用了一个辅助类,.products 注入了正确的 url。

产品类别:

class Product: Codable {
    let id: String
    let name: String?
}

然后使用这些产品来填充下拉列表。现在我要做的是让这些离线可用,所以基本上第一次启动应用程序时我想将产品保存到核心数据,然后在后续启动时我们只检索存储的列表。

因此,我使用名为 ProductCD 的实体构建了一个核心数据模型,并将我的 retrieveProducts 方法更改如下:

private func saveProductsToCD() {
    API.client.call(.products, expecting: [Product].self) { (result, products) in
        switch result {
        case .failure:
            print("Unable to retrieve products")
        case .success:
            guard let productResponse = products else { return }
            for product in productResponse {
                product.mapToCoreData()
            }
            DispatchQueue.main.async {
                self.appDelegate.saveContext()
                self.getSavedProducts()
            }
        }
    }
}

internal func getSavedProducts() {
// First I attempt to retrieve the list from core data

    let context = appDelegate.persistentContainer.viewContext
    let request: NSFetchRequest<ProductCD> = ProductCD.fetchRequest()
    do {
        productsList = try context.fetch(request)
    } catch {
        print("Error fetching data from context \(error)")
    }
 // If no data available in core data I call the method above to hit the 
 // products endpoint and save to core data, then I retrieve the products

    if productList.count == 0 {
        self.saveProductsToCD()
    }
}

我在 Product 类上添加了 mapToCoreData 方法:

class Product: Codable {
    let id: String
    let name: String?
    
    internal func mapToCoreData() {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext
        let storedProduct = ProductCD(context: context)
        
        storedProduct.id = self.id
        storedProduct.name = self.name ?? ""
    }
}

因此,虽然这是一种工作,但存在问题。数据正在被存储和调用,但是由于线程问题(我猜)我收到了警告和一些偶尔的崩溃:

1-警告:在我的产品类中,我收到以下警告:

UIApplication.delegate must be used from main thread only

我尝试将调用包装在 DispatchQueue.Main.async 中,但我仍然收到消息。

2-有时在加载时,我的应用程序崩溃并显示以下消息:

Thread 9: EXC_BAD_ACCESS (code=1, address=0x0)

在我的产品类的这一行:

let storedProduct = ProductCD(context: context)

当我在本质上试图检索核心数据库的文本字段中键入时,会发生此错误。

此崩溃仅在启动时偶尔发生,因此我确定这是线程问题,但不确定如何解决。

标签: swiftmultithreadingcore-data

解决方案


推荐阅读