Swift 4 可编码领域对象子类
Posted
技术标签:
【中文标题】Swift 4 可编码领域对象子类【英文标题】:Swift 4 Codable Realm Object Subclasses 【发布时间】:2017-11-02 16:59:49 【问题描述】:试图将我的一些代码库切换到 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:)
,我就会收到以下错误:
我不确定解决这些问题的正确方法是什么。
【问题讨论】:
不支持RealmObjects之间的继承 看起来应该支持对象之间的继承:realm.io/docs/swift/latest/#model-inheritance 【参考方案1】:您不能覆盖 init()
或 Realm Object
的其他初始化程序。您可以改用便捷初始化程序。那么你不能调用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)
【讨论】:
【参考方案2】:你不能只覆盖一个类的初始化器。如果您要覆盖,请为所有这些覆盖。如果您并不真正使用或关心其他初始化程序,至少只需在其中调用 super.<respective init>
。
对于init(realm: RLMRealm, schema: RLMObjectSchema)
和init(value: Any, schema: RLMSchema)
,编译器会抱怨它不知道RLMRealm、RLMObjectSchema 和RLMSchema 是什么。所以除了 RealmSwift 之外还要导入 Realm。
【讨论】:
【参考方案3】:正如我刚刚在 another question, 上回答的那样,虽然您可以按照上面 Katsumi 的建议将您的子类用作 Codable 类型,但您可能会遇到另一个问题。
您不能将 Base
的集合作为包含子类实例的引用类型并使该集合在 Codable 中存在。它只会解码为Base
实例。
多态持久性似乎被设计破坏了。
错误报告SR-5331 引用了他们在Radar. 上得到的回复
与现有的 NSCoding API (NSKeyedArchiver) 不同,为了灵活性和安全性,新的 Swift 4 Codable 实现不会将有关编码类型的类型信息写入生成的档案中。因此,在解码时,API 只能使用您提供的具体类型来解码值(在您的情况下是超类类型)。
这是设计使然——如果您需要执行此操作所需的动力,我们建议您采用 NSSecureCoding 并使用 NSKeyedArchiver/NSKeyedUnarchiver
我不为所动,从所有精彩的文章中想到 Codable 是我的一些祈祷的答案。作为对象工厂的一组并行 Codable 结构是我正在考虑的一种解决方法,以保留类型信息。
【讨论】:
以上是关于Swift 4 可编码领域对象子类的主要内容,如果未能解决你的问题,请参考以下文章