I am using reflection in Swift to write a generic object (Any) to dictionary in Swift; both for educational purposes and production purposes too.
The code works but one of my tests showed that for self-referential classes, it does not work properly.
When accessing the referenced member field whose type is same as the class, the Mirror.child.label field returns a value of some
as the dictionary key , before accessing the member's variables.
A good example:
class Node{
var next: Node!
var val: Int = 0
init(_ val: Int){
self.val = val
}
}
let node = Node(4)
node.next = Node(5)
node.next.next = Node(6)
print("node.toDictionary: " , toDictionary(obj: node))
The output is:
node.toDictionary: ["val": 4, "next": ["some": ["next": ["some": ["val": 6, "next": [:]]], "val": 5]]]
Needless to say, the expected output is:
["next": ["next": ["val": 6],"val": 5],"val": 4]
The minimal code for toDictionary
which produces this error is:
func toDictionary(obj: Any) -> [String:Any] {
var dict = [String:Any]()
let otherObj = Mirror(reflecting: obj)
for child in otherObj.children {
if let key = child.label {
if child.value is String || child.value is Character || child.value is Bool
|| child.value is Int || child.value is Int8 || child.value is Int16 || child.value is Int32 || child.value is Int64
|| child.value is UInt || child.value is UInt8 || child.value is UInt16 || child.value is UInt32 || child.value is UInt64
|| child.value is Float || child.value is Float32 || child.value is Float64 || child.value is Double
{
dict[key] = child.value
}
else if child.value is [String] || child.value is [Character] || child.value is [Bool]
|| child.value is [Int] || child.value is [Int8] || child.value is [Int16] || child.value is [Int32] || child.value is [Int64]
|| child.value is [UInt] || child.value is [UInt8] || child.value is [UInt16] || child.value is [UInt32] || child.value is [UInt64]
|| child.value is [Float] || child.value is [Float32] || child.value is [Float64] || child.value is [Double]{
let array = child.value as! [Any]
dict[key] = array
}else if child.value is [Any]{
let array = child.value as! [Any]
var arr:[Any] = []
for any in array{
arr.append(toDictionary(obj: any))
}
dict[key] = arr
}
else{
dict[key] = toDictionary(obj: child.value)
}
}
}
return dict
}
Why is the Mirror.child.label
field not handling self-referential classes properly?
Aucun commentaire:
Enregistrer un commentaire