本文「打造强大的BaseModel」的第四篇,《打造强大的BaseModel(1):让Model自我描述》、《打造强大的BaseModel(2):让Model实现自动映射,将字典转化成Model》、《打造强大的BaseModel(3):让Model实现自动归档》。如果你没有看过前面三篇文章的话,建议在看这篇文章之前先去看看,熟悉一下iOS Runtime的一些东西以及纯Swift类型和Objc类型的异同。
而这篇文章则讨论了Swift的反射功能,与iOS Runtime不一样,Swift的反射用了另一套API,实现机制也完全不一样,倒是和目前其他的面向对象语言有些相似,比如C#和Java。不过Swift作为一门很新的语言,目前正在高速发展中,其反射功能和和主流的高级语言还没法比,但是我相信Apple会在将来大大加强Swift的反射功能,以追上目前主流语言的脚步。
iOS Runtime目前存在的问题
关于iOS Runtime的文章有很多,一搜就能找出一大堆,但是大多数都是介绍什么是iOS Runtime及怎么使用Runtime。其实基于Objc的Runtime是iOS开发的黑魔法,甚至可以是说奇技淫巧,比如神奇的Method Swizzle可以交换任何iOS的系统方法,在里面加上自己定义的一些功能。再比如消息转发机制,又比如说一些位于中的方法,比如class_copyIvarList等方法,可以动态获取一个类里面所有的方法和属性,还有就是动态给一个类添加属性和方法。Objc的Runtime是如此的强大,再加上KVC和KVO这两个利器,可以实现很多你根本就想不到的功能,给iOS开发带来极大的便捷。
使用iOS Runtime好处非常多,但缺点也是显而易见的,主要有下面几个:
- 基于Objc的Runtime不是类型安全的,需要开发者保证所有数据都是正确的类型。
- Runtime还是需要进行数据类型的检查,影响了执行效率。
- 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有了冲突,那么Swift语言里有没有类似于Objc的Runtime的一套机制,让Swift数据类型也能实现Objc的Runtime的一些功能呢?
很遗憾,这个答案是NO,Swift目前只有有限的反射功能,完全不能和Objc的Runtime相比。
什么是反射
反射是一种计算机处理方式。是程序可以访问、检测和修改它本身状态或行为的一种能力。
上面的话来自百度百科。使用反射有什么用,看一些iOS Runtime的文章应该会很明白。下面再列举一下
- 动态地创建对象和属性,
- 动态地获取一个类里面所有的属性,方法。
- 获取它的父类,或者是实现了什么样的接口(协议)
- 获取这些类和属性的访问限制(Public 或者 Private)
- 动态地获取运行中对象的属性值,同时也能给它赋值(KVC)
- 动态调用实例方法或者类方法
- 动态的给类添加方法或者属性,还可以交换方法(只限于Objective-C)
上面的一系列功能的细节和计算机语言的不同而不同。对于Objective-C来说,位于中的一系列方法就是完成这些功能的,严格来说Runtime并不是反射。而Swift真正拥有了反射功能,但是功能非常弱,目前只能访问和检测它本身,还不能修改。
Swift的反射
Swift的反射机制是基于一个叫Mirror的Stuct来实现的。具体的操作方式为:首先创建一个你想要反射的类的实例,再传给Mirror的构造器来实例化一个Mirror对象,最后使用这个Mirror来获取你想要的东西。
首先我们来写一些测试用的类
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
protocol Drive{ func run() } public class Tire{ //轮胎 var brand:String? //品牌 var size:Float = 0 //大小 } public class Vehicle:Drive{ var carType:String? var tires:[Tire]? var host:String?// 主人 var brand:String?//汽车品牌 func run() { if let h = host{ print("(h)Drive a (brand) (carType) car run") } else{ print("this car is not selled") } } } public class Trunk:Vehicle{ public var packintBox:String? } public struct TranGroup{ //货运集团 private var trunks = { return [Trunk]() }() var country:String? var turnover:Float? } //一个中国的货运集团 var tranGroup = TranGroup(trunks: [Trunk](), country: "China", turnover: 123456789.111) let trunk1 = Trunk() trunk1.brand = "MAN" trunk1.host = "Stan" trunk1.packintBox = "Big And Long" tranGroup.trunks.append(trunk1) let mirrorTran = Mirror(reflecting: tranGroup) print(tranGroup) //打印出 Mirror for TranGroup print(mirrorTran.subjectType) //打印出 TranGroup print(mirrorTran.displayStyle) //Optional(Swift.Mirror.DisplayStyle.Struct),是个Struct类型 print(mirrorTran.superclassMirror()) //nil,因为没有父类 for (key,value) in mirrorTran.children{ print("(key) : (value)") } //打印结果 Optional("trunks") : [DemoConsole.Trunk] Optional("country") : Optional("China") Optional("turnover") : Optional(1.23457e+08) |
可以看出,和第一篇文章一样,打印出个每个属性和其值。不同的是,对于自定义对象,不能自动打出里面的属性内容。
在利用Swift的反射来改进BaseModel之前,让我们来看看Mirror里面都有什么东西吧
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 2 /" target="_blank">打造强大的BaseModel(1):让Model自我描述》、《打造强大的BaseModel(2):让Model实现自动映射,将字典转化成Model》、《打造强大的BaseModel(3):让Model实现自动归档》。如果你没有看过前面三篇文章的话,建议在看这篇文章之前先去看看,熟悉一下iOS Runtime的一些东西以及纯Swift类型和Objc类型的异同。
而这篇文章则讨论了Swift的反射功能,与iOS Runtime不一样,Swift的反射用了另一套API,实现机制也完全不一样,倒是和目前其他的面向对象语言有些相似,比如C#和Java。不过Swift作为一门很新的语言,目前正在高速发展中,其反射功能和和主流的高级语言还没法比,但是我相信Apple会在将来大大加强Swift的反射功能,以追上目前主流语言的脚步。 iOS Runtime目前存在的问题关于iOS Runtime的文章有很多,一搜就能找出一大堆,但是大多数都是介绍什么是iOS Runtime及怎么使用Runtime。其实基于Objc的Runtime是iOS开发的黑魔法,甚至可以是说奇技淫巧,比如神奇的Method Swizzle可以交换任何iOS的系统方法,在里面加上自己定义的一些功能。再比如消息转发机制,又比如说一些位于中的方法,比如class_copyIvarList等方法,可以动态获取一个类里面所有的方法和属性,还有就是动态给一个类添加属性和方法。Objc的Runtime是如此的强大,再加上KVC和KVO这两个利器,可以实现很多你根本就想不到的功能,给iOS开发带来极大的便捷。 使用iOS Runtime好处非常多,但缺点也是显而易见的,主要有下面几个:
其中前面两个问题影响不大,关键在于第三个。基于Swift作为一门静态语言,所有数据的类型都是在编译时就确定好了的,但是Apple为了让Swift兼容Objc,让Swift也使用了Runtime。这显然会拖累Swift的运行效率,和Apple所宣称Swift具有超越Objective-C的性能的观点完全不符。而Swift在将来是会慢慢替代 Objective-C的成为iOS或者OSX开发的主流语言,所以为了性能,我们应该尽量使用原生的Swift数据类型,避免让Runtime进行Swift类型->Objc类型的隐式转换。 所以目前的问题是使用Swift原生的数据类型和想要使用Objc的Runtime有了冲突,那么Swift语言里有没有类似于Objc的Runtime的一套机制,让Swift数据类型也能实现Objc的Runtime的一些功能呢? 很遗憾,这个答案是NO,Swift目前只有有限的反射功能,完全不能和Objc的Runtime相比。 什么是反射
上面的话来自百度百科。使用反射有什么用,看一些iOS Runtime的文章应该会很明白。下面再列举一下
上面的一系列功能的细节和计算机语言的不同而不同。对于Objective-C来说,位于中的一系列方法就是完成这些功能的,严格来说Runtime并不是反射。而Swift真正拥有了反射功能,但是功能非常弱,目前只能访问和检测它本身,还不能修改。 Swift的反射Swift的反射机制是基于一个叫Mirror的Stuct来实现的。具体的操作方式为:首先创建一个你想要反射的类的实例,再传给Mirror的构造器来实例化一个Mirror对象,最后使用这个Mirror来获取你想要的东西。 首先我们来写一些测试用的类
可以看出,和第一篇文章一样,打印出个每个属性和其值。不同的是,对于自定义对象,不能自动打出里面的属性内容。 在利用Swift的反射来改进BaseModel之前,让我们来看看Mirror里面都有什么东西吧
|