Swift 4 Codable Realm对象子类
试图将我的一些代码库转换为Swift 4的新的漂亮的Codable
协议。 我的设置看起来像这样:
class Base: Object, Codable { dynamic var id: String = "" dynamic var timestamp: String = "" private enum CodingKeys: String, CodingKey { case id = "_id" case timestamp = "timestamp" } } class User: Base { dynamic var name: String = "" private enum CodingKeys: String, CodingKey { case name = "name" } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .name) try super.init(from: decoder) } }
我有一个符合Codable
的基础领域对象类,以及一个Base
的子类,它也有自己的编码密钥。 我覆盖User
子类上的init(decoder:)
来映射我的附加编码密钥,然后调用super.init(decoder:)
来映射Base
的编码密钥。 但是,一旦我覆盖init(decoder:)
我会收到以下错误:
- 必需的初始化程序’init()’必须由’Base’的子类提供
- 必需的初始化程序’init(realm:schema :)’必须由’Base’的子类提供
- 必需的初始化程序’init(value:schema :)’必须由’Base’的子类提供
我不确定解决这些问题的正确方法是什么。
您不能覆盖Realm Object
init()
或其他初始值设定项。 您可以使用便利初始化程序。 然后你不能调用super.init(from:)
,所以定义一个解码超类’属性的方法,如Base.decode(from:)
。
请参阅以下代码示例:
class Base: Object, Codable { dynamic var id: String = "" dynamic var timestamp: String = "" private enum CodingKeys: String, CodingKey { case id = "_id" case timestamp = "timestamp" } func decode(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decode(String.self, forKey: .id) self.timestamp = try container.decode(String.self, forKey: .timestamp) } } class User: Base { dynamic var name: String = "" private enum CodingKeys: String, CodingKey { case id = "_id" case timestamp case name = "name" } required convenience init(from decoder: Decoder) throws { self.init() try decode(from: decoder) let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .name) } }
您不能只覆盖一个类的一个初始值设定项。 如果要覆盖,请为所有这些操作。 如果你没有真正使用或关心其他初始化器,那么至少要调用super.
。
对于init(realm: RLMRealm, schema: RLMObjectSchema)
和init(value: Any, schema: RLMSchema)
编译器会抱怨它不知道RLMRealm,RLMObjectSchema和RLMSchema是什么。 因此除了RealmSwift之外还要导入Realm。
正如我刚刚回答的另一个问题,虽然您可以使用上面的Katsumi建议将您的子类用作Codable类型,但您可能遇到另一个问题。
您不能将Base
集合作为包含子类实例的引用类型,并使该集合在Codable中存在。 它只会解码为Base
实例。
多态持久性似乎被设计破坏了 。
错误报告SR-5331引用了他们对雷达的反应。
与现有的NSCoding API(NSKeyedArchiver)不同,新的Swift 4 Codable实现不会将编码类型的类型信息写入生成的归档中,以实现灵活性和安全性。 因此,在解码时,API只能使用您提供的具体类型来解码值(在您的情况下,超类类型)。
这是设计 – 如果您需要执行此操作所需的动态,我们建议您采用NSSecureCoding并使用NSKeyedArchiver / NSKeyedUnarchiver
我没有打动,从所有发光文章中想到,Codable是我祈祷的答案。 作为对象工厂的一组并行的Codable结构是我正在考虑的一种解决方法,用于保存类型信息。