DynamicNodeEncoding Works with List Type, but Not with List's Element Type
owenzhao opened this issue · comments
Zhao Xin commented
// Model
class Foo:Object, Codable, DynamicNodeEncoding {
enum CodingKeys: String, CodingKey {
case id
case numbers = "number"
}
static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
switch key {
case CodingKeys.id:
return .attribute
default:
return .element
}
}
@objc dynamic var id = ObjectId.generate()
let numbers = List<Bar>()
override class func primaryKey() -> String? {
return "id"
}
}
class Bar:Object, Codable, DynamicNodeEncoding {
enum CodingKeys: String, CodingKey {
case id
}
static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
switch key {
case CodingKeys.id:
return .attribute
default:
return .element
}
}
@objc dynamic var id = ObjectId.generate()
override class func primaryKey() -> String? {
return "id"
}
}
// code
let foo = Foo()
foo.numbers.append(objectsIn:[Bar(),Bar(),Bar()])
let encoder = XMLEncoder()
encoder.outputFormatting = .prettyPrinted
let encodedXML = try! encoder.encode(foo, withRootKey: "foo")
let str = String(data: encodedXML, encoding: .utf8)
print(str!)
Results:
<foo id="606bedefcd66ce1115c94be3">
<number>
<id>606bedefcd66ce1115c94be6</id>
</number>
<number>
<id>606bedefcd66ce1115c94be7</id>
</number>
<number>
<id>606bedefcd66ce1115c94be8</id>
</number>
</foo>
Expected:
The id
s in number should be attributes instead of elements.
If I change let numbers = List<Bar>()
to var numbers = [Bar]()
, the issue is gone. So I think there must be something wrong here and I don't know what to do next. As the Realm requests to use List
instead of Array
here. Any suggestions?
Zhao Xin commented
Solved. I read the source code of XMLCoder, and in DynamicNodeEncoding.swift
, there is
extension Array: DynamicNodeEncoding where Element: DynamicNodeEncoding {
public static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
return Element.nodeEncoding(for: key)
}
}
So I make it as a copy for List
extension List: DynamicNodeEncoding where Element: DynamicNodeEncoding {
public static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
return Element.nodeEncoding(for: key)
}
}
// results
<foo id="606bf34ba0066ab968b69b2b">
<number id="606bf34ba0066ab968b69b2e" />
<number id="606bf34ba0066ab968b69b2f" />
<number id="606bf34ba0066ab968b69b30" />
</foo>
And it worked. So I guess for people who use Realm, you should do this too.