Swift中的反射

关键词

Swift 反射 Mirror

Representation of the sub-structure and optional "display style" of any arbitrary subject instance.

Describes the parts---such as stored properties, collection elements, tuple elements, or the active enumeration case---that make up a particular instance. May also supply a "display style" property that suggests how this structure might be rendered.
/// A collection of `Child` elements describing the structure of the
/// reflected subject.
public let children: Children

/// Suggests a display style for the reflected subject.
public let displayStyle: Mirror.DisplayStyle?
@warn_unused_result
public func superclassMirror() -> Mirror?

children记录了该object下的变量(注:此处object为广义的定义)
displayStyle表示该object的类型(同上)
superclassMirror,顾名思义,表示其父类的Mirror

public enum DisplayStyle {
        case Struct
        case Class
        case Enum
        case Tuple
        case Optional
        case Collection
        case Dictionary
        case Set
    }

根据displayStyle的类型去判断类型再做分类讨论,其中Optional是Swift中独有比较特别的类型,需要特殊处理,当displayStyle为nil时,表示为基本数据类型

最后通过superclassMirror一层一层递归,去遍历所有变量

func getModel(dic:Dictionary<String, Any>, objName:String) -> MYDataModel {
        let modelClass = NSClassFromString(objName) as! MYDataModel.Type
        model = modelClass.init()
        var mirror:Mirror? = Mirror(reflecting: model)
        while (mirror != nil) {
            traverseProperty(dic, mirror, model)
            mirror = mirror!.superclassMirror()
        }
        return model
    }

private func traverseProperty(dic:Dictionary<String, Any>, _ mirror:Mirror?, _ model:MYDataModel) {
        if (mirror == nil) {
            return
        } else {
            for (_,value) in mirror!.children.enumerate() {
                let propertyName:String = value.label == nil ? "" : value.label!
                let properValue = value.value
                let dictionaryValue = dic[propertyName]
                let tmp = Mirror(reflecting: properValue)
                if (dictionaryValue != nil) {
                    if (tmp.displayStyle != nil) {
                        switch tmp.displayStyle! {
                        case .Class:
                            if let dicValue = dictionaryValue as? [String: String] {
                                let anyClass = model.classForCoder as? NSObject.Type
                                let arrayTypeName = anyClass!.performSelector(Selector("\(propertyName)Type")).takeRetainedValue() as? String
                                let anyArrayClass = NSClassFromString(arrayTypeName!) as! MYDataModel.Type
                                let obj = anyArrayClass.init()
                                traverseProperty(dicValue, Mirror(reflecting: obj), obj)
                                model.setValue(obj, forKey: propertyName)
                            }
                        case .Collection:
                            let anyClass = model.classForCoder as? NSObject.Type
                            let arrayTypeName = anyClass!.performSelector(Selector("\(propertyName)Type")).takeRetainedValue() as? String
                            switch arrayTypeName! {
                            case MYDataModelType.String.rawValue:
                                if let arrayValue =  dictionaryValue as? [String] {
                                    if (arrayValue.count > 0) {
                                        model.setValue(arrayValue, forKey: propertyName)
                                    }
                                }
                            default:
                                if let arrayValue =  dictionaryValue as? [[String: String]] {
                                    var resultArray = [(NSClassFromString(arrayTypeName!) as! MYDataModel.Type).init()]
                                    for item in arrayValue {
                                        let anyArrayClass = NSClassFromString(arrayTypeName!) as! MYDataModel.Type
                                        let obj = anyArrayClass.init()
                                        traverseProperty(item, Mirror(reflecting: obj), obj)
                                        resultArray.append(obj)
                                    }
                                    model.setValue(resultArray, forKey: propertyName)
                                }
                                break
                            }
                        case .Dictionary:
                            print("Dictionary")
                        case .Optional:
                            if (tmp.children.count > 0) {
                                for (_,value2) in tmp.children.enumerate() {
                                    let properValue2 = value2.value
                                    switch properValue2 {
                                    case _ as Bool:
                                        if let boolValue =  dictionaryValue as? Bool {
                                            model.setValue(NSNumber(bool:boolValue), forKey: propertyName)
                                        }
                                    case _ as Int:
                                        if let intValue =  dictionaryValue as? Int {
                                            model.setValue(NSNumber(integer: intValue), forKey: propertyName)
                                        }
                                    case _ as Float :
                                        if let floatValue =  dictionaryValue as? Float {
                                            model.setValue(NSNumber(float: floatValue), forKey: propertyName)
                                        }
                                    case _ as Double :
                                        if let doubleValue =  dictionaryValue as? Double {
                                            model.setValue(NSNumber(double: doubleValue), forKey: propertyName)
                                        }
                                    case _ as String:
                                        if let stringValue =  dictionaryValue as? String {
                                            model.setValue(stringValue, forKey: propertyName)
                                        }
                                    default:
                                        print("\(propertyName) is an unkown optional value")
                                        break
                                    }
                                }
                            } else {
                                print("\(propertyName) is an unkown value")
                                if let objValue =  dictionaryValue as? AnyObject {
                                    model.setValue(objValue, forKey: propertyName)
                                }
                            }
                        default:
                            break
                        }
                    } else {
                        switch properValue {
                        case _ as Bool:
                            if let boolValue =  dictionaryValue as? Bool {
                                model.setValue(NSNumber(bool:boolValue), forKey: propertyName)
                            }
                        case _ as Int:
                            if let intValue =  dictionaryValue as? Int {
                                model.setValue(NSNumber(integer: intValue), forKey: propertyName)
                            }
                        case _ as Float :
                            if let floatValue =  dictionaryValue as? Float {
                                model.setValue(NSNumber(float: floatValue), forKey: propertyName)
                            }
                        case _ as Double :
                            if let doubleValue =  dictionaryValue as? Double {
                                model.setValue(NSNumber(double: doubleValue), forKey: propertyName)
                            }
                        case _ as String:
                            if let stringValue =  dictionaryValue as? String {
                                model.setValue(stringValue, forKey: propertyName)
                            }
                        default:
                            break
                        }
                    }
                }

            }
        }
    }

源码地址:https://github.com/VictorWuSH/SwiftExercise

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值