vendredi 28 août 2020

Value of a child from mirror introspection not conformed to protocol anymore

I am trying to understand swift's inflection capabilities. I have a parent Passport class whose child (User) implements a protocol Clonable, however when introspecting the child value, it fails the check child.value is Clonable. Can someone explain this?

extension Clonable {
    func clone() -> Self? {
        if let me = self as? SimpleInit {
            let new = type(of: me).init()
            let mirror = Mirror(reflecting: self)
            for child in mirror.children {
                if let kp = child.label, let new = new as? NSObject {
                    if child.value is Clonable, let value = child.value as? Clonable { // this should be true
                        print("cloning \(child.value) for keypath \(kp)")
                        new.setValue(value.clone(), forKeyPath: kp)
                    } else {
                        print("not cloning \(child.value) for keypath \(kp)")
                        new.setValue(child.value, forKeyPath: kp)
                    }
                }
            }
            return new as? Self
        }
        return nil
    }
}

class Passport: NSObject, Clonable, SimpleInit, CustomReflectable {
    var customMirror: Mirror {
        return Mirror(self, children: ["user": user])
    }
    @objc var user: User?
    
    required override init() {
    }
    
    func printMe() {
        user?.printMe()
    }
}

class User: NSObject, Clonable, SimpleInit, CustomReflectable {
    var customMirror: Mirror {
        return Mirror(self, children: ["name": name])
    }
    @objc var id: Int
    @objc var name: String?
    
    required override init() {
        print("init user")
        id = Int(arc4random())
    }
    
    func printMe() {
        print("id \(id) name \(name)")
    }
}


let passport = Passport()
passport.user = User()
passport.user?.name = "John"
let clone = passport.clone()

passport.printMe()
clone?.printMe()

This is the output:

init user // should be called second time when user gets cloned.
not cloning Optional(<__lldb_expr_92.User: 0x6000039d6420>) for keypath user
id 2046302380 name Optional("John")
id 2046302380 name Optional("John")




Aucun commentaire:

Enregistrer un commentaire