Swift Runtime
深入了解过Objective-C
这门语言的人一定知道,这是一门动态语言。在日常的开发中,也常常会使用到Runtime
对自己的项目做一些小"手脚",比如说替换这些视图控制器的viewWillAppear
方法让他们在启动的时候能在自己的事件日志中记录一下,或者是记录一下这个视图控制器的时间;或者是对某个模型做一些便利化的操作,比如说动态的获取到模型里边的属性名称,然后自动的encode
与decode
,将JSON
自动的转为Model
之类的操作。
Swift
问世到现在已经有段时间了,从最开始的不稳定、BUG
、各种各样的调整到现在稳定的版本Swift2.2
,有一部分"喜新厌旧"的人已经正式的投入到了Swift
开发之中,我认识的朋友也有几个把他们用到了真正的项目开发中,每次总是向我们这些OC
的开发者在抱怨,这玩意编译好慢、这Swift
好像有很多种写法啊,更像是面向接口开发,确实,当你看到一些Bind
,RAC
等库的时候,眼花缭乱的,可能需要细细的看才能知道这个方法的来龙去脉,而我感觉OC
与Swift
两种语言对于开发者来说,若是想做一个不错的iOS
开发者,OC
一定是不能丢弃的,毕竟这门老语言已经成熟了很久,枝叶茂密,Swift
任然是襁褓中的婴儿,有待培养、研究。
进入正题,为了便于大家的理解,我们这里的实验类有2个,一个是纯Swift类,另外一个继承于NSObject
测试类- Runtime,获取属性与方法
按照我们在OC使用Runtime的方法,同样的写一遍就好了。
Swift的基本语法知识这里就不说了-。-
然后调用看一下打印的结果
调用代码- TestSwiftClass (纯Swift的类),并不能获取到属性与方法
- ViewController (继承
UIViewController
的类,也就是继承NSObject
), 可以打印, 但是大家仔细看一下,我们自己加入了returnInt
与returnTuple
的方法,returnInt
有打印,但是tuple
却没有。
这是为什么?
- 纯
Swift
类的函数调用已经不再是OC
的运行时发消息objc_msgsend
,而是类似C++
的vtable
,在编译时就确定了调用什么函数,所以runtime
获取不到。 - 继承于
NSObject
的类依然拥有动态性,所以可以拿的到。
-OC
的runtime
特性就是,所有的运行时方法都依赖TypeEncoding
,他指定了方法的参数类型以及函数在调用时参数入栈所需要的内存空间,没有这个标识就无法动态的压入参数。返回类型Tuple
,也就是元组,是Swift
特有的,无法映射到OC
的类型,也无法用OC
的TypeEncoding
表示,所以也无法通过runtime
获取。
m_type: Optional("q24@0:8q16")
上边代码的解释在这里:
代码解释
Type Encoding扩展阅读1
Type Encoding扩展阅读2
Type Encoding官网文档
- 方法的替换
在OC
项目中,想必大部分人都使用了这个Method Swizzling
,替换一些系统类的方法为自己的方法,以提供便捷(Hook
)。
- 对于纯
Swift
类来说,我们上边的方法证实了无法通过runtime
得到,所以不可以替换 - 对于继承于
NSObject
的类来说,通过runtime
可以获取到的方法可以完成替换,那些没有type Encoding
的方法也就不能替换了。我们再次写代码来确认一下runtime
拿到的方法可以进行替换,我们替换viewDidAppear:
试一下。
确认可以交换。最后打印 des
。 但是奇怪的事情出现了,这个时候我也想替换一下returnInt
这个方法,但是却发现不可以了。所以我们加断点看一下调试信息。我们可以看到,在my_ViewDidAppear
前,有@objc
这样一个小玩意在,而大家单独调试returnInt
却没有。
@objc
@objc
是用来将Swift的API导出给OC与OC runtime使用的,如果你继承NSObject的类,将会被自动的加入这个标识。
这样一来,真相大白,我们给之前的纯Swift类加上这个标识看一下效果。
代码这样,属性与方法名全部打印了出来。
dynamic
同时,还有这个,文档中有一句说明,加了@objc
标识的方法、属性都无法保证都会被运行时调用,因为Swift
会做静态优化。要想完全被动态调用就要使用dynamic
修饰词了。使用这个标识也会隐形的加入@objc
。这也就解释了为什么上边VC中的方法无法被替换了,被Swift优化成静态调用了,而ViewDidAppear
本身为OC
的方法,拥有动态特性,所以我们加入dynamic
关键字
这样,结果打印2喽,成功的动态替换。
今天文章就写到这里啦。
手机淘宝技术团队MTT
今天发布了这篇Swift Runtime分析: 还像OC Runtime一样么
文章,细读之后给更多的人分享出来。也希望读者在看到这篇文章的时候打开Xcode,新建一个工程来实际测试一下。
CopyRight@Dylan 2015-3-31 愚人节快乐。