与iOS Runtime不一样,Swift的反射用了另一套API,实现机制也完全不一样

1. iOS Runtime

  • 其实基于Objc的Runtime是iOS开发的黑魔法,比如神奇的Method Swizzle可以交换任何iOS的系统方法, 再比如消息转发机制,又如class_copyIvarList等方法,可以动态获取一个类裡面所有的方法和属性, 以及动态给一个类新增属性和方法.
  • Objc的Runtime是如此的强大,再加上KVC和KVO这两个利器,可以实现很多你根本就想不到的功能,给iOS开发带来极大的便捷。

2. Apple推出全新的Swift语言后,单纯的Swift型别不再兼容Objc的Runtime,

Swift作为一门静态语言,所有资料的型别都是在编译时就确定好了的,但是Apple为了让Swift相容Objc,让Swift也使用了Runtime。这显然会拖累Swift的执行效率,和Apple所宣称Swift具有超越Objective-C的效能的观点完全不符。而Swift在将来是会慢慢替代 Objective-C的成为iOS或者OSX开发的主流语言,所以为了效能,我们应该尽量使用原生的Swift,避免让Runtime进行Swift型别->Objc型别的隐式转换。
Swift目前只有有限的反射功能,完全不能和Objc的Runtime相比。

首先作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发公众号:编程大鑫,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!

什么是反射

反射是一种计算机处理方式。是程式可以访问、检测和修改它本身状态或行为的一种能力。
上面的话来自百度百科。使用反射有什么用,看一些iOS Runtime的文章应该会很明白。下面再列举一下

  • 动态地建立物件和属性,
  • 动态地获取一个类裡面所有的属性,方法。
  • 获取它的父类,或者是实现了什么样的介面(协议)
  • 获取这些类和属性的访问限制(Public 或者 Private)
  • 动态地获取执行中物件的属性值,同时也能给它赋值(KVC)
  • 动态呼叫例项方法或者类方法
  • 动态的给类新增方法或者属性,还可以交换方法(只限于Objective-C)

上面的一系列功能的细节和计算机语言的不同而不同。对于Objective-C来说,位于中的一系列方法就是完成这些功能的,严格来说Runtime并不是反射。而Swift真正拥有了反射功能,但是功能非常弱,目前只能访问和检测它本身,还不能修改。

Swift的反射

Swift的反射机制是基于一个叫Mirror的Stuct来实现的。具体的操作方式为:首先建立一个你想要反射的类的例项,再传给Mirror的构造器来例项化一个Mirror物件,最后使用这个Mirror来获取你想要的东西。

Mirror结构体常用属性:
subjectType:对象类型
children:反射对象的属性集合
displayStyle:反射对象展示类型

下面来简单介绍下Mirror的使用:

  1. 获取对象类型
  2. 获取一个类的属性名称和属性的值
        let p = Person()
        p.name = "刘伟湘"
        p.age = 22

        let mirror:Mirror = Mirror(reflecting: p)

        /*
         *  1\. 获取对象类型
         */
        print("获取对象类型:\(mirror.subjectType)")
        //打印结果:  获取对象类型:Person

        /*
         *   2\. 获取对象的所有属性名称和属性值
         */
        for property in mirror.children {
            let propertyNameStr = property.label!  // 属性名使用!,因为label是optional类型
            let propertyValue = property.value    // 属性的值
            print("\(propertyNameStr)的值为:\(propertyValue)")
            //打印结果: name的值为:Optional("刘伟湘")  age的值为:22
        }

swfit反射的应用场景现在还比较狭窄,因为功能还不够完善,比较常见的反射应用场景就是自定义类模型转字典

class NewViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationItem.title = "new"
        self.view.backgroundColor = .white

        // 创建一个User实例对象模型
        let user1 = User()
        user1.name = "刘伟湘"
        user1.age = 100
        user1.emails = ["506299396.qq.com","111111111111.qq.com"]
        let tel1 = Telephone(title: "手机", number: "18711112222")
        let tel2 = Telephone(title: "公司座机", number: "2800034")
        user1.tels = [tel1, tel2]

        // 模型转字典
        if let model = user1.toJSONModel() {
            print(model)
        }
        /*
         *打印结果
         ["age": 100, "tels": ["item0": ["number": "18711112222", "title": "手机"], "item1": ["number": "2800034", "title": "公司座机"]], "emails": ["item0": "506299396.qq.com", "item1": "111111111111.qq.com"], "name": "刘伟湘"]
         *
         */
    }
}

class User {
    var name:String = ""
    var nickname:String?
    var age:Int?
    var emails:[String]?
    var tels:[Telephone]?
}

// 电话结构体
struct Telephone {
    var title:String   // 电话标题
    var number:String  // 电话号码
}

// 自定义一个JSON协议
protocol Sam_JSON {
    func toJSONModel() -> Any?
}

// 扩展协议方法,实现一个通用的toJSONModel方法(反射实现)
extension Sam_JSON {
    // 将模型数据转成可用的字典数据,Any表示任何类型,除了方法类型
    func toJSONModel() -> Any? {
        // 根据实例创建反射结构体Mirror
        let mirror = Mirror(reflecting: self)

        if mirror.children.count > 0  {
            // 创建一个空字典,用于后面添加键值对
            var result: [String:Any] = [:]

            for (idx, children) in mirror.children.enumerated() {
                let propertyNameString = children.label ?? "item\(idx)"
                let value = children.value
                // 判断value的类型是否遵循JSON协议,进行深度递归调用
                if let jsonValue = value as? Sam_JSON {
                    result[propertyNameString] = jsonValue.toJSONModel()
                }
            }
            return result
        }
        return self
    }
}

// 扩展可选类型,使其遵循JSON协议,可选类型值为nil时,不转化进字典中
extension Optional: Sam_JSON {
    func toJSONModel() -> Any? {
        if let x = self {
            if let value = x as? Sam_JSON {
                return value.toJSONModel()
            }
        }
        return nil
    }
}

// 扩展两个自定义类型,使其遵循JSON协议
extension User: Sam_JSON { }
extension Telephone: Sam_JSON { }

// 扩展Swift的基本数据类型,使其遵循JSON协议
extension String: Sam_JSON { }
extension Int: Sam_JSON { }
extension Bool: Sam_JSON { }
extension Dictionary: Sam_JSON { }
extension Array: Sam_JSON { }