NSManagedObject and Codable for class stored in server and local storage

邮差的信 提交于 2019-12-13 20:36:15

问题


I am creating a class that represents data that is either in local storage or comes in from online. On runtime I will use a get request to get an array of these objects from a server and compare them to the existing ones in CoreData in order to determine a new set of objects to be used for the app and to be stored.

As such I have created a CoreData managed class that represents my object as such it inherits NSManagedObject. This will allow me to deal with the local storage getting the array in storage and putting back a new one after the app has finished.

I would then like to make this class Codable that way I can implement the required public init(from decoder: Decoder) method that allows me to get my array of objects like this in the get request. JSONDecoder().decode([DataClass].self, from: data!).

There are two ways I am trying to do this and neither of them are working.

Problems:

I have a private enum CodingKeys: String, CodingKey {...} in class scope and using that to encode works great but for whatever reason that triggers an error that says that the class doesn't implement encode which I have no intention of implementing. I am not sure why that matters.

I can put the enum inside the scope of the initializer but if I do that a new problem pops up. I must call a designated initializer of NSManagedObject. This is a problem because that call requires a NSManagedObjectContext which I dont have.

As an alternative:

I have create a method func getDataClass(from decoder: Decoder) -> DataClass? however this also brings with it two problems. I still must initialize a DataClass object somehow and I have no clue how to bring that into the JSONDecoder().decode([DataClass].self, from: data!) line.


回答1:


You have to make DataClass conform to Codable.

First of all create two extensions to be able to pass the NSManagedObjectContext in the userInfo dictionary of the JSONDecoder.

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

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

The following example uses only one attribute name in DataClass.
The Codable methods must be in the class not in the CoreDataProperties extension.

class DataClass: NSManagedObject, Codable {

    private enum CodingKeys: String, CodingKey { case name }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
    }

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

To use the decoder you have to use the initializer

let context = // get the managed object context
let decoder = JSONDecoder(context: context)


来源:https://stackoverflow.com/questions/52459182/nsmanagedobject-and-codable-for-class-stored-in-server-and-local-storage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!