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