简体   繁体   中英

Store JSON Data in to CoreData

i want to download a JSON from an API and store the Objects into CoreData. The downloading and decoding of the JSON works but I have problems to store the Objects directly into CoreData.

I tried to create an entity for my Objects but the App don't save the Objects to CoreData.

I always get the Error: Unresolved error nilError, The operation couldn't be completed. (Foundation._GenericObjCError error 0.). Don't know why it's not working anymore

I use this to download and decode the 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()
    }
}

And this to store into 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
    }
}

How do I save the objects in CoreData?

Thanks for the help.

I recommend to make CoreItem conform to Decodable .

First of all create two extensions to be able to pass the NSManagedObjectContext instance in JSONDecoder

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

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

Implement the required Decodable method in 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)
    }
}

The dataTask code can be reduced to

  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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM