首页 > 解决方案 > 将 JSON 数据存储到 CoreData

问题描述

我想从 API 下载 JSON 并将对象存储到 CoreData 中。JSON的下载和解码工作但我无法将对象直接存储到CoreData中。

我试图为我的对象创建一个实体,但应用程序没有将对象保存到 CoreData。

我总是收到错误:未解决的错误 nilError,操作无法完成。(Foundation._GenericObjCError 错误 0。)。不知道为什么它不再工作了

我用它来下载和解码 JSON:

class ItemDownloader: ObservableObject {

    @Published var items: Items = [Item]()

    @Environment(\.managedObjectContext) var managedObjectContext


    let itemEndpoint = „https:…………“

    init() {
        guard let url = URL(string: itemEndpoint) else { return }
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            do {
                guard let data = data else { return }
                let items = try JSONDecoder().decode(Items.self, from: data)
                print(items)
                DispatchQueue.main.async {
                    self.items = items

                    }

                    do {
                        guard let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] else {return}


                        let coreitems: [CoreItem] = jsonArray.compactMap { [weak self] in
                            guard
                            let name = $0["name"] as? String,
                            let id = $0["id"] as? Int16
                                else {return nil  }
                            print(name)
                            print(id)


                            let coreitem = CoreItem(context: self!.managedObjectContext)
                            coreitem.name = name
                            coreitem.id = id

                            print(coreitem.name)
                            print(coreitem.id)


                            return coreitem

                                }

                        do{
                          try self.managedObjectContext.save()
                        } catch{
                            print(error)
                        }
                        print(coreitems)
                        print(NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last!);



                    }

               } catch {
                print("Error decoding JSON: ", error)
            }
        }.resume()
    }
}

并将其存储到 CoreData 中:


public class CoreItem: NSManagedObject, Identifiable {
    @NSManaged public var name: String
    @NSManaged public var id: Int16

}

extension CoreItem {

    static func getAllCoreItems() -> NSFetchRequest <CoreItem> {
        let request:NSFetchRequest<CoreItem> = CoreItem.fetchRequest() as!
        NSFetchRequest<CoreItem>

        let sortDescriptor = NSSortDescriptor(key: "id", ascending: true)

        request.sortDescriptors = [sortDescriptor]

        return request
    }
}

如何在 CoreData 中保存对象?

谢谢您的帮助。

标签: jsonswiftswiftui

解决方案


我建议使CoreItem符合Decodable.

首先创建两个扩展,以便能够将NSManagedObjectContext实例传入JSONDecoder

extension CodingUserInfoKey {
    static let context = CodingUserInfoKey(rawValue: "context")!
}

extension JSONDecoder {
    convenience init(context: NSManagedObjectContext) {
        self.init()
        self.userInfo[.context] = context
    }
}

实现所需的Decodable方法CoreItem

public class CoreItem: NSManagedObject, Identifiable, Decodable {
    @NSManaged public var name: String
    @NSManaged public var id: Int16

    private enum CodingKeys: String, CodingKey { case name, id}

    public required convenience init(from decoder: Decoder) throws {
       guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Error: NSManagedObjectContext not available") }
       let entity = NSEntityDescription.entity(forEntityName: "CoreItem", in: context)!
       self.init(entity: entity, insertInto: context)
       let values = try decoder.container(keyedBy: CodingKeys.self)
       name = try values.decode(String.self, forKey: .name)
       id = try values.decode(Int16.self, forKey: .id)
    }
}

dataTask代码可以简化为

  URLSession.shared.dataTask(with: url) { (data, response, error) in
        do {
            guard let data = data else { return }
            let decoder = JSONDecoder(context: self.managedObjectContext)
            let coreitems = try decoder.decode([CoreItem].self, from: data)
            print(coreitems)      
            try self.managedObjectContext.save()
        } catch {
          print(error)
        }
    }.resume()

推荐阅读