Codable似乎是一个非常令人兴奋的功能。但我想知道如何在核心数据中使用它?特别是,是否可以直接从/向NSManagedObject编码/解码JSON?
我尝试了一个非常简单的例子:
并自己定义了Foo:
import CoreData @objc(Foo) public class Foo: NSManagedObject,Codable {}
但是当像这样使用它时:
let json = """ { "name": "foo","bars": [{ "name": "bar1",}],[{ "name": "bar2" }] } """.data(using: .utf8)! let decoder = JSONDecoder() let foo = try! decoder.decode(Foo.self,from: json) print(foo)
编译器因此错误而失败:
super.init isn't called on all paths before returning from initializer
我想我可能做错了,因为我甚至没有传递NSManagedObjectContext,但我不知道在哪里坚持它。
Core Data是否支持Codable?
您可以将Codable接口与CoreData对象一起使用来对数据进行编码和解码,但是它不像使用普通的旧swift对象那样自动化。以下是如何使用Core Data对象直接实现JSON解码:
首先,使对象实现Codable。必须在对象上定义此接口,而不是在扩展中定义。您还可以在此课程中定义编码密钥。
class MyManagedObject: NSManagedObject,Codable { @NSManaged var property: String? enum CodingKeys: String,CodingKey { case property = "json_key" } }
接下来,您可以定义init方法。这也必须在类方法中定义,因为Decodable协议需要init方法。
required convenience init(from decoder: Decoder) throws { }
但是,与托管对象一起使用的正确初始化程序是:
NSManagedObject.init(entity: NSEntityDescription,into context: NSManagedObjectContext)
所以,这里的秘密是使用userInfo字典将适当的上下文对象传递给初始化器。为此,您需要使用新密钥扩展CodingUserInfoKey结构:
extension CodingUserInfoKey { static let context = CodingUserInfoKey(rawValue: "context") }
现在,您可以作为上下文的解码器:
required convenience init(from decoder: Decoder) throws { guard let context = decoder.userInfo[.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) }
现在,当您为托管对象设置解码时,您需要传递正确的上下文对象:
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
要编码数据,您需要使用编码协议功能执行类似操作。