Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
706 views
in Technique[技术] by (71.8m points)

inheritance - Swift 2.0 Get Mirrored Superclass Properties

I need to get the properties of my class as a dictionary. For simplicity, I created a protocol which has a default implementation as follows:

protocol ListsProperties{
    func toDictionary() -> [String: AnyObject]
}

extension ListsProperties{
    func toDictionary() -> [String: AnyObject] {
        let mirrored_object = Mirror(reflecting: self)
        var dict = [String: AnyObject]()
        for (_, attr) in mirrored_object.children.enumerate() {
            if let propertyName = attr.label as String! {
                dict[propertyName] = attr.value as? AnyObject
            }
        }     

        return dict
    }
}

My classes can conform to this protocol and will have the toDictionary() method available. However, this does not work if I use the method on a subclass, as it will produce only the properties defined on the subclass and ignore the parent superclass properties.

Ideally I could find some way to call the toDictionary() method on the mirrored superclass as this would then call toDictionary() on its own superclass and the compiler says that the superclass mirror does not conform to the Protocol even though the class it is mirroring does.

The following works but only if there is only one superclass so isn't sufficient:

func toDictionary() -> [String: AnyObject] {
    let mirrored_object = Mirror(reflecting: self)
    var dict = [String: AnyObject]()
    for (_, attr) in mirrored_object.children.enumerate() {
        if let propertyName = attr.label as String! {
            dict[propertyName] = attr.value as? AnyObject
        }
    }

    // This is an issue as it limits to one subclass 'deep' 
    if let parent = mirrored_object.superclassMirror(){
        for (_, attr) in parent.children.enumerate() {
            if let propertyName = attr.label as String!{
                if dict[propertyName] == nil{
                    dict[propertyName] = attr.value as? AnyObject
                }
            }
        }
    }

    return dict
}

Any ideas on how I could modify the default implementation of toDictionary() to include superclass attributes (and the attributes of any superclasses of the superclass etc)?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

One possible solution would be to implement toDictionary() as a method of Mirror itself, so that you can traverse recursively to the superclass mirror:

extension Mirror {

    func toDictionary() -> [String: AnyObject] {
        var dict = [String: AnyObject]()

        // Properties of this instance:
        for attr in self.children {
            if let propertyName = attr.label {
                dict[propertyName] = attr.value as? AnyObject
            }
        } 

        // Add properties of superclass:
        if let parent = self.superclassMirror() {
            for (propertyName, value) in parent.toDictionary() {
                dict[propertyName] = value
            }
        }

        return dict
    }
}

and then use that to implement the protocol extension method:

extension ListsProperties {
    func toDictionary() -> [String: AnyObject] {
        return Mirror(reflecting: self).toDictionary()
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...