且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在核心数据中使用swift 4 Codable?

更新时间:2022-03-14 01:05:58

您可以将Codable接口与CoreData对象一起使用,以对数据进行编码和解码,但是它不像与普通的旧swift对象一起使用时那样自动。直接使用Core Data对象实现JSON解码的方法如下:

You can use the Codable interface with CoreData objects to encode and decode data, however it's not as automatic as when used with plain old swift objects. Here's how you can implement JSON Decoding directly with Core Data objects:

首先,使对象实现Codable。此接口必须在对象上定义,而不是在扩展中定义。您也可以在此类中定义编码键。

First, you make your object implement Codable. This interface must be defined on the object, and not in an extension. You can also define your Coding Keys in this class.

class MyManagedObject: NSManagedObject, Codable {
    @NSManaged var property: String?

    enum CodingKeys: String, CodingKey {
       case property = "json_key"
    }
}

接下来,您可以定义init方法。这也必须在class方法中定义,因为Decodable协议需要使用init方法。

Next, you can define the init method. This must also be defined in the class method because the init method is required by the Decodable protocol.

required convenience init(from decoder: Decoder) throws {
}

用于托管对象的初始化程序是:

However, the proper initializer for use with managed objects is:

NSManagedObject.init(entity: NSEntityDescription, into context: NSManagedObjectContext)

所以,这里的秘密是使用 userInfo 字典来将适当的上下文对象传递给初始化程序。为此,您需要使用新的密钥扩展 CodingUserInfoKey 结构:

So, the secret here is to use the userInfo dictionary to pass in the proper context object into the initializer. To do this, you'll need to extend the CodingUserInfoKey struct with a new key:

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

现在,您可以作为上下文的解码器:

Now, you can just as the decoder for the context:

required convenience init(from decoder: Decoder) throws {

    guard let context = decoder.userInfo[CodingUserInfoKey.context!] as? NSManagedObjectContext else { fatalError() }
    guard let entity = NSEntityDescription.entity(forEntityName: "MyManagedObject", in: context) else { fatalError() }

    self.init(entity: entity, in: context)

    let container = decoder.container(keyedBy: CodingKeys.self)
    self.property = container.decodeIfPresent(String.self, forKey: .property)
}

现在,当您设置托管对象的解码时,您需要传递适当的上下文对象:

Now, when you set up the decoding for Managed Objects, you'll need to pass along the proper context object:

let data = //raw json data in Data object
let context = persistentContainer.newBackgroundContext()
let decoder = JSONDecoder()
decoder.userInfo[.context] = context

_ = try decoder.decode(MyManagedObject.self, from: data) //we'll get the value from another context using a fetch request later...

try context.save() //make sure to save your data once decoding is complete

要对数据进行编码,您需要使用 encoding 进行类似的操作协议功能。

To encode data, you'll need to do something similar using the encode protocol function.