• Swift


    1,反射(Reflection)

    对于C#、Java开发人员来说,肯定都对反射这个概念相当熟悉。所谓反射就是可以动态获取类型、成员信息,同时在运行时(而非编译时)可以动态调用任意方法、属性等行为的特性。

    以Java上的两个知名框架(hibernate和spring)为例。hibernate的属性映射就是通过反射来赋值的,spring的bean的创建就是根据配置的class来反射构建的。
     
    2,Objective-C 的 Runtime
    在使用ObjC开发时很少强调其反射概念,因为ObjC的Runtime要比其他语言中的反射强大的多。在ObjC中可以很简单的实现字符串和类型的转换(NSClassFromString()),实现动态方法调用(performSelector: withObject:),动态赋值(KVC)等等。
     
    3,Swift中的反射
    在Swift中并不提倡使用Runtime,而是像其他语言一样使用反射(Reflect)。当然,目前Swift中的反射还没有其他语言中的反射功能强大,不仅远不及OC的Runtime,离Java的反射也有一定的距离。
    Swift的反射机制是基于一个叫 Mirror 的 struct 来实现的,其内部有如下属性和方法:
    1
    2
    3
    4
    let children: Children   //对象的子节点。
    displayStyle: Mirror.DisplayStyle?   //对象的展示风格
    let subjectType: Any.Type   //对象的类型
    func superclassMirror() -> Mirror?   //对象父类的 mirror

    4,Swift反射的使用样例

    样例1:输出实体对象的类名,属性个数,以及所有属性的属性名和属性值。
    首先定义一个用户类:
    1
    2
    3
    4
    5
    6
    7
    //用户类
    class User {
        var name:String ""  //姓名
        var nickname:String?  //昵称
        var age:Int?   //年龄
        var emails:[String]?  //邮件地址
    }
    接着创建一个用户对象,并通过反射获取这个对象的信息:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //创建一个User实例对象
    let user1 = User()
    user1.name = "hangge"
    user1.age = 100
    user1.emails = ["hangge@hangge.com","system@hangge.com"]
             
    //将user对象进行反射
    let hMirror = Mirror(reflecting: user1)
             
    print("对象类型:(hMirror.subjectType)")
    print("对象子元素个数:(hMirror.children.count)")
             
    print("--- 对象子元素的属性名和属性值分别如下 ---")
    for case let (label?, value) in hMirror.children {
        print("属性:(label)     值:(value)")
    }
    控制台输出信息如下:  
    原文:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)
     
     
    样例2:通过属性名(字符串)获取对应的属性值,并对值做类型判断(包括是否为空)
    首先为方便使用,这里定义两个方法。getValueByKey()是用来根据传入的属性名字符串来获取对象中对应的属性值。unwrap()是用来给可选类型拆包的(对于非可选类型则返回原值)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //根据属性名字符串获取属性值
    func getValueByKey(obj:AnyObject, key: String) -> Any {
        let hMirror = Mirror(reflecting: obj)
        for case let (label?, value) in hMirror.children {
            if label == key {
                return unwrap(value)
            }
        }
        return NSNull()
    }
     
    //将可选类型(Optional)拆包
    func unwrap(any:Any) -> Any {
        let mi = Mirror(reflecting: any)
        if mi.displayStyle != .Optional {
            return any
        }
         
        if mi.children.count == 0 { return any }
        let (_, some) = mi.children.first!
        return some
    }
    下面是实际测试样例,同样用上例的User对象做测试:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    //创建一个User实例对象
    let user1 = User()
    user1.name = "hangge"
    user1.age = 100
    user1.emails = ["hangge@hangge.com","system@hangge.com"]
     
    //通过属性名字符串获取对应的值
    let name = getValueByKey(user1, key: "name")
    let nickname = getValueByKey(user1, key: "nickname")
    let age = getValueByKey(user1, key: "age")
    let emails = getValueByKey(user1, key: "emails")
    let tel = getValueByKey(user1, key: "tel")
    print(name, nickname, age, emails, tel)
     
    //当然对于获取到的值也可以进行类型判断
    if name is NSNull {
        print("name这个属性不存在")
    }else if (name asAnyObject) == nil {
        print("name这个属性是个可选类型,且为nil")
    }else if name is String {
        print("name这个属性String类型,其值为:(name)")
    }
     
    if nickname is NSNull {
        print("nickname这个属性不存在")
    }else if (nickname asAnyObject) == nil {
        print("nickname这个属性是个可选类型,且为nil")
    }else if nickname is String {
        print("nickname这个属性String类型,其值为:(nickname)")
    }
     
    if tel is NSNull {
        print("tel这个属性不存在")
    }else if (tel asAnyObject) == nil {
        print("tel这个属性是个可选类型,且为nil")
    }else if tel is String {
        print("tel这个属性String类型,其值为:(tel)")
    }
    控制台输出信息如下:
    原文:Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)
     
     
    附:通过KVC访问属性值
    KVC是key-value coding的缩写。它是一种间接访问对象的机制。其本质是依据OC中Runtime的强大动态能力来实现的。在Swift中,只要类继承NSObject即可使用KVC。(有一个叫KVO的,它又是基于KVC,大家有兴趣的可以自行研究下。)
    KVC中:key的值就是属性名称的字符串,返回的value是任意类型,需要自己转化为需要的类型。
    (注意:正由于KVC是基于Objective-C的,所以其不支持可选类型(optional)的属性,比如上例的 var age:Int? 
    因此用户类做如下改造:)
    1
    2
    3
    4
    5
    6
    7
    //用户类
    class UserNSObject{
        var name:String ""  //姓名
        var nickname:String?  //昵称
        var age:Int = 0  //年龄
        var emails:[String]?  //邮件地址
    }
    KVC主要就是两个方法:
    (1)通过key获得对应的属性值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    //创建一个User实例对象
    let user1 = User()
    user1.name = "hangge"
    user1.age = 100
    user1.emails = ["hangge@hangge.com","system@hangge.com"]
     
    //使用KVC取值
    let name = user1.valueForKey("name")
    let nickname = user1.valueForKey("nickname")
    let age = user1.valueForKey("age")
    let emails = user1.valueForKey("emails")
    //let tel = user1.valueForKey("tel")
    print(name, nickname, age, emails)
     
             
    //当然对于获取到的值也可以进行类型判断
    if name == nil {
        print("name这个属性是个可选类型,且为nil")
    }else if name is String {
        print("name这个属性String类型,其值为:(name)")
    }
           
    if nickname == nil {
        print("nickname这个属性是个可选类型,且为nil")
    }else if nickname is String {
        print("nickname这个属性String类型,其值为:(nickname)")
    }
    (2)通过key设置对应的属性值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //创建一个User实例对象
    let user1 = User()
     
    //使用KVC赋值
    user1.setValue("hangge", forKey: "name")
    user1.setValue(100, forKey: "age")
    user1.setValue(["hangge@hangge.com","system@hangge.com"], forKey: "emails")
             
    print(user1.name, user1.nickname, user1.age, user1.emails)


    原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_976.html

    http://www.hangge.com/blog/cache/detail_976.html

  • 相关阅读:
    用wifi调试android程序
    【翻译】Ext JS 4.1的性能
    index range scan,index fast full scan,index skip scan发生的条件
    柱状图(Histogram),绑定变量,bind peeking,cursor_sharing 之间的关系1 柱状图
    柱状图(Histogram),绑定变量,bind peeking,cursor_sharing 之间的关系3 柱状图与cursor_sharing
    JNI开发入门
    索引的Clustering Factor
    索引选择性
    列定义允许null,可能导致Index Hint提升不走索引
    柱状图(Histogram),绑定变量,bind peeking,cursor_sharing 之间的关系2 绑定变量与柱状图
  • 原文地址:https://www.cnblogs.com/feng9exe/p/9105757.html
Copyright © 2020-2023  润新知