轉(zhuǎn)自:http://blog.csdn.net/judy_luo/article/details/51025210
Swift是否和OC一樣有runtime機(jī)制
OC語(yǔ)言最大的特性無(wú)疑是其的動(dòng)態(tài)性,可以利用OC的動(dòng)態(tài)性能夠獲得一個(gè)類(lèi)的方法和屬性,從而實(shí)現(xiàn)靈活的程序,但Swift是否也包含了runtime機(jī)制呢?
參考鏈接:http://mp.weixin.qq.com/s?__biz=MzA3ODg4MDk0Ng==&mid=403153173&idx=1&sn=c631f95b28a0eb4b842a9494e43a30e5&scene=23&srcid=0331ZwO8t6uWiBON621r1GhC#rd
下面我們將從純Swift的類(lèi)和繼承OC的Swift類(lèi)來(lái)闡述Swift的runtime機(jī)制
分析用例:
方法,屬性
動(dòng)態(tài)性最重要的一點(diǎn)就是拿到某個(gè)類(lèi)的方法和屬性,使用如下的方法打印類(lèi)的方法和屬性
調(diào)用showClsRuntime打印方法
打印如下:
對(duì)于純Swift的TestASwiftClass來(lái)說(shuō)任何方法、屬性都未獲取到。
對(duì)于TestSwiftClass來(lái)說(shuō)除testReturnTuple、testReturnVoidWithaCharacter兩個(gè)方法外,其他的都獲取成功了。
這是為什么呢?
1:純Swift類(lèi)的函數(shù)調(diào)用已經(jīng)不是OC那樣的運(yùn)行時(shí)消息了,而是類(lèi)似C++似得vtable,在編譯時(shí)就確定了調(diào)用那個(gè)函數(shù)了.
2:而TestSwiftClass繼承自UIViewController也就是NSObject,Swift為了兼容OC,所以繼承自NSObject的類(lèi)都保留了他的動(dòng)態(tài)性,所以我們能通過(guò)runtime拿到他的屬性和方法.
可是為什么testReturnTuple、testReturnVoidWithaCharacter這兩個(gè)函數(shù)卻無(wú)法通過(guò)runtime獲得呢?
從OC的動(dòng)態(tài)特性可知,所有運(yùn)行時(shí)方法都依賴(lài)TypeEcoding,也就是method_getTypeEncoding函數(shù),它指定了參數(shù)類(lèi)型以及參數(shù)在入棧時(shí)的內(nèi)存空間,沒(méi)有這個(gè)標(biāo)識(shí)則沒(méi)法入棧.而元祖,和字符類(lèi)型是Swift獨(dú)有的,所以不能利用runtime獲得他的方法.
方法替代
動(dòng)態(tài)性最常用的方法就是方法替代,將某個(gè)類(lèi)的方法替代為自定義的方法,從而起到hook的作用.
對(duì)于純Swift類(lèi)(如TestASwiftClass)來(lái)說(shuō),無(wú)法通過(guò)objc runtime替換方法,因?yàn)橛缮厦娴?a target="_blank" rel="nofollow">測(cè)試可知拿不到這些方法、屬性
對(duì)于繼承自NSObject類(lèi)(如TestSwiftVC)來(lái)說(shuō),無(wú)法通過(guò)runtime獲取到的方法肯定沒(méi)法替換了。那能通過(guò)runtime獲取到的方法就都能被替換嗎?我們測(cè)一把
Method Swizzling的代碼如下
找到官方文檔讀讀。
可以知道@objc是用來(lái)將Swift的API導(dǎo)出給Objective-C和Objective-C runtime使用的,如果你的類(lèi)繼承自O(shè)bjective-c的類(lèi)(如NSObject)將會(huì)自動(dòng)被編譯器插入@objc標(biāo)識(shí)。
我們?cè)诎裈estASwiftClass(純Swift類(lèi))的方法、屬性前都加個(gè)@objc 試試,如圖:
文檔里還有一句說(shuō)明:
加了@objc標(biāo)識(shí)的方法、屬性無(wú)法保證都會(huì)被運(yùn)行時(shí)調(diào)用,因?yàn)镾wift會(huì)做靜態(tài)優(yōu)化。要想完全被動(dòng)態(tài)調(diào)用,必須使用dynamic修飾。使用dynamic修飾將會(huì)隱式的加上@objc標(biāo)識(shí)。
這也就解釋了為什么testReturnVoidWithaId無(wú)法被替換,因?yàn)閷?xiě)在Swift里的代碼直接被編譯優(yōu)化成靜態(tài)調(diào)用了。
而viewDidAppear是繼承Objective-C類(lèi)獲得的方法,本身就被修飾為dynamic,所以能被動(dòng)態(tài)替換。