[英]Swift 4 Codable Realm Object Subclasses
trying to switch some of my codebase over to Swift 4's new nifty Codable
protocol. 试图将我的一些代码库转换为Swift 4的新的漂亮的
Codable
协议。 My setup looks something like this: 我的设置看起来像这样:
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)
}
}
I have a base realm object class that conforms to Codable
, and a subclass of Base
that also has it's own coding keys. 我有一个符合
Codable
的基础领域对象类,以及一个Base
的子类,它也有自己的编码密钥。 I override init(decoder:)
on the User
subclass to map my additional coding keys, then call super.init(decoder:)
to map Base
's coding keys. 我覆盖
User
子类上的init(decoder:)
来映射我的附加编码密钥,然后调用super.init(decoder:)
来映射Base
的编码密钥。 However, once I override init(decoder:)
I get the following errors: 但是,一旦我覆盖
init(decoder:)
我会收到以下错误:
I'm not sure what the correct way is to go about fixing these issues. 我不确定解决这些问题的正确方法是什么。
You cannot override init()
or other initializers of Realm Object
. 您不能覆盖Realm
Object
init()
或其他初始值设定项。 You can use convenience initializer instead. 您可以使用便利初始化程序。 Then you cannot call
super.init(from:)
, so define a method that decodes superclass' properties like Base.decode(from:)
. 然后你不能调用
super.init(from:)
,所以定义一个解码超类'属性的方法,如Base.decode(from:)
。
See following code sample: 请参阅以下代码示例:
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)
}
}
You cannot override just one initializer of a class. 您不能只覆盖一个类的一个初始值设定项。 If you are going to override, do it for all of them.
如果要覆盖,请为所有这些操作。 If you don't really use or care about the other initializers just at least call
super.<respective init>
in them. 如果你没有真正使用或关心其他初始化器,那么至少要调用
super.<respective init>
。
For init(realm: RLMRealm, schema: RLMObjectSchema)
and init(value: Any, schema: RLMSchema)
compiler is going to complain that it doesn't know what RLMRealm, RLMObjectSchema and RLMSchema are. 对于
init(realm: RLMRealm, schema: RLMObjectSchema)
和init(value: Any, schema: RLMSchema)
编译器会抱怨它不知道RLMRealm,RLMObjectSchema和RLMSchema是什么。 So import Realm besides RealmSwift. 因此除了RealmSwift之外还要导入Realm。
As I just answered on another question, whilst you may be able to use your subclass as a Codable type with Katsumi's advice above, you may run into another gotcha. 正如我刚刚回答的另一个问题,虽然您可以使用上面的Katsumi建议将您的子类用作Codable类型,但您可能遇到另一个问题。
You cannot have collections of Base
as a reference type that contain subclass instances and have that collection survive Codable. 您不能将
Base
集合作为包含子类实例的引用类型,并使该集合在Codable中存在。 It will only decode as Base
instances. 它只会解码为
Base
实例。
Polymorphic persistence appears to be broken by design . 多态持久性似乎被设计破坏了 。
The bug report SR-5331 quotes the response they got on their Radar. 错误报告SR-5331引用了他们对雷达的反应。
Unlike the existing NSCoding API (NSKeyedArchiver), the new Swift 4 Codable implementations do not write out type information about encoded types into generated archives, for both flexibility and security. 与现有的NSCoding API(NSKeyedArchiver)不同,新的Swift 4 Codable实现不会将编码类型的类型信息写入生成的归档中,以实现灵活性和安全性。 As such, at decode time, the API can only use the concrete type your provide in order to decode the values (in your case, the superclass type).
因此,在解码时,API只能使用您提供的具体类型来解码值(在您的情况下,超类类型)。
This is by design — if you need the dynamism required to do this, we recommend that you adopt NSSecureCoding and use NSKeyedArchiver/NSKeyedUnarchiver 这是设计 - 如果您需要执行此操作所需的动态,我们建议您采用NSSecureCoding并使用NSKeyedArchiver / NSKeyedUnarchiver
I am unimpressed, having thought from all the glowing articles that Codable was the answer to some of my prayers. 我没有打动,从所有发光文章中想到,Codable是我祈祷的答案。 A parallel set of Codable structs that act as object factories is one workaround I'm considering, to preserve type information.
作为对象工厂的一组并行的Codable结构是我正在考虑的一种解决方法,用于保存类型信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.