Codable 似乎是一个非常令人兴奋的功能。但我想知道我们如何在 Core Data 中使用它?特别是,是否可以直接从/向 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
目标文件是定义Foo
我想我可能做错了,因为我什至没有传递 NSManagedObjectContext
,但我不知道该把它贴在哪里。
Core Data 是否支持Codable
?
最佳答案
您可以将 Codable 接口(interface)与 CoreData 对象一起使用来编码和解码数据,但是它不像与普通的旧 swift 对象一起使用时那样自动。以下是如何直接使用 Core Data 对象实现 JSON 解码:
首先,让您的对象实现 Codable。此接口(interface)必须在对象上定义,而不是在扩展中定义。您还可以在此类中定义您的编码键。
class MyManagedObject: NSManagedObject, Codable {
@NSManaged var property: String?
enum CodingKeys: String, CodingKey {
case property = "json_key"
}
}
接下来,您可以定义 init 方法。这也必须在类方法中定义,因为 Decodable 协议(protocol)需要 init 方法。
required convenience init(from decoder: Decoder) throws {
}
但是,用于托管对象的正确初始化程序是:
NSManagedObject.init(entity: NSEntityDescription, into context: NSManagedObjectContext)
所以,这里的秘诀是使用 userInfo 字典将正确的上下文对象传递到初始化程序中。为此,您需要使用新 key 扩展 CodingUserInfoKey
结构:
extension CodingUserInfoKey {
static let context = CodingUserInfoKey(rawValue: "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)
}
现在,当您为托管对象设置解码时,您需要传递正确的上下文对象:
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
要对数据进行编码,您需要使用编码 协议(protocol)函数执行类似的操作。
关于swift - 如何在核心数据中使用 swift 4 Codable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51504410/