Swift Runtime分析

分析用例

我們拿一個(gè)純Swift類和一個(gè)繼承自NSObject的類的類來做分析,這兩個(gè)類里包含盡量多的Swift的類型比如Character、String垛玻、AnyObject摹察、Tuple。

代碼如下:

方法碧囊、屬性

動(dòng)態(tài)性比較重要的一點(diǎn)就是能夠拿到某個(gè)類所有的方法树灶、屬性,我們使用如下代碼來打印方法和屬性列表糯而。

調(diào)用showClsRuntime的代碼如下:

看看我們得到什么結(jié)果天通?

對(duì)于純Swift的TestASwiftClass來說任何方法、屬性都未獲取到熄驼。

對(duì)于TestSwiftVC來說除testReturnTuple像寒、testReturnVoidWithaCharacter兩個(gè)方法外,其他的都獲取成功了瓜贾。

這是為什么诺祸?

純Swift類的函數(shù)調(diào)用已經(jīng)不再是Objective-c的運(yùn)行時(shí)發(fā)消息,而是類似C++的vtable祭芦,在編譯時(shí)就確定了調(diào)用哪個(gè)函數(shù)筷笨,所以沒法通過runtime獲取方法、屬性龟劲。

TestSwiftVC繼承自UIViewController胃夏,基類NSObject,而Swift為了兼容Objective-C咸灿,凡是繼承自NSObject的類都會(huì)保留其動(dòng)態(tài)性构订,所以我們能通過runtime拿到他的方法。

但為什么testReturnTuple?testReturnVoidWithaCharacter卻又獲取不到呢避矢?

從Objective-c的runtime 特性可以知道悼瘾,所有運(yùn)行時(shí)方法都依賴TypeEncoding囊榜,也就是method_getTypeEncoding返回的結(jié)果,他指定了方法的參數(shù)類型以及在函數(shù)調(diào)用時(shí)參數(shù)入棧所要的內(nèi)存空間亥宿,沒有這個(gè)標(biāo)識(shí)就無法動(dòng)態(tài)的壓入?yún)?shù)(比如testReturnVoidWithaId: Optional("v24@0:8@16") Optional("v")卸勺,表示此方法參數(shù)共需24個(gè)字節(jié),返回值為void烫扼,第一個(gè)參數(shù)為id曙求,第二個(gè)為selector,第三個(gè)為id)映企,而Character和Tuple是Swift特有的悟狱,無法映射到OC的類型,更無法用OC的typeEncoding表示堰氓,也就沒法通過runtime獲取了挤渐。

Method Swizzling

動(dòng)態(tài)性最常用的就是方法替換(Method Swizzling),將類的某個(gè)方法替換成自定義的方法双絮,從而達(dá)到hook的作用浴麻。

對(duì)于純Swift類(如TestASwiftClass)來說,無法通過objc runtime替換方法囤攀,因?yàn)橛缮厦娴臏y(cè)試可知拿不到這些方法软免、屬性

對(duì)于繼承自NSObject類(如TestSwiftVC)來說,無法通過runtime獲取到的方法肯定沒法替換了焚挠。那能通過runtime獲取到的方法就都能被替換嗎膏萧?我們測(cè)一把。

Method Swizzling的代碼如下

我們替換兩個(gè)可以被runtime獲取到的方法:viewDidAppear和testReturnVoidWithaId

打印的日志為

F:testReturnVoidWithaId L:50

F:sz_viewDidAppear L:46

說明viewDidAppear已經(jīng)被替換蝌衔,但是testReturnVoidWithaId卻沒有被替換向抢,這是為何?

我們?cè)诜椒ɡ锎騻€(gè)斷點(diǎn)看看,如圖:

可以看到區(qū)別胚委,調(diào)用sz_viewDidAppear棧的前一幀為@objc TestSwiftVC.sz_viewDidAppear(Bool) -> ()有個(gè)@objc標(biāo)識(shí),而調(diào)用testReturnVoidWithaId則沒有此標(biāo)識(shí)叉信。

@objc用來做什么的亩冬?與動(dòng)態(tài)性有關(guān)嗎?

@objc

找到官方文檔讀讀硼身。

可以知道@objc是用來將Swift的API導(dǎo)出給Objective-C和Objective-C runtime使用的硅急,如果你的類繼承自O(shè)bjective-c的類(如NSObject)將會(huì)自動(dòng)被編譯器插入@objc標(biāo)識(shí)。

我們?cè)诎裈estASwiftClass(純Swift類)的方法佳遂、屬性前都加個(gè)@objc 試試营袜,如圖:

查看日志可以發(fā)現(xiàn)加了@objc的方法、屬性均可以被runtime獲取到了丑罪。

dynamic

文檔里還有一句說明:

加了@objc標(biāo)識(shí)的方法荚板、屬性無法保證都會(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無法被替換免绿,因?yàn)閷懺赟wift里的代碼直接被編譯優(yōu)化成靜態(tài)調(diào)用了唧席。

而viewDidAppear是繼承Objective-C類獲得的方法,本身就被修飾為dynamic嘲驾,所以能被動(dòng)態(tài)替換淌哟。

我們把TestSwiftVC方法前加上dynamic再測(cè)一把,如圖:

從堆棧也可以看出辽故,方法的調(diào)用前增加了@objc標(biāo)識(shí)丙猬,testReturnVoidWithaId方法被替換成功了。

同樣的做法孔轴,我們把TestASwiftClass的方法和屬性也都加上dynamic修飾杀糯,做Method Swizzling,同樣獲得成功彤枢,如圖

Objective-C獲取Swift runtime信息

在Objective-c代碼里使用objc_getClass("TestSwiftVC");會(huì)發(fā)現(xiàn)返回值為空狰晚,這是為什么?Swift代碼中的TestSwiftVC類缴啡,在OC中還是這個(gè)名字嗎壁晒?

我們初始化一個(gè)對(duì)象,并斷點(diǎn)和打印看看业栅,如下圖:

可以看到Swift中的TestSwiftVC類在OC中的類名已經(jīng)變成TestSwift.TestSwiftVC秒咐,即規(guī)則為SWIFT_MODULE_NAME.類名稱,在普通源碼項(xiàng)目里SWIFT_MODULE_NAME即為ProductName碘裕,在打好的Cocoa Touch Framework里為則為導(dǎo)出的包名携取。

所以要想從Objective-c中獲取Swift類的runtime信息得這樣寫:

Objective-C替換Swift函數(shù)

給TestSwiftVC和TestASwiftClass的testReturnVoidWithaId函數(shù)加上dynamic修飾,然后我們?cè)贠bjective-C代碼里替換為testReturnVoidWithaIdImp函數(shù):

運(yùn)行之后我們得到結(jié)果

F:void testReturnVoidWithaIdImp(__strong id, SEL, __strong id) L:20 self=

F:void testReturnVoidWithaIdImp(__strong id, SEL, __strong id) L:20 self=TestSwift.TestASwiftClass

說明兩者的方法在加上dynamic修飾后帮孔,均能在Objective-c里被替換雷滋。(TestSwiftVC的testReturnVoidWithaId不加dynamic也會(huì)打印日志,為什么文兢?留給讀者思考)

總結(jié)

純Swift類沒有動(dòng)態(tài)性晤斩,但在方法、屬性前添加dynamic修飾可以獲得動(dòng)態(tài)性姆坚。

繼承自NSObject的Swift類澳泵,其繼承自父類的方法具有動(dòng)態(tài)性,其他自定義方法兼呵、屬性需要加dynamic修飾才可以獲得動(dòng)態(tài)性兔辅。

若方法的參數(shù)腊敲、屬性類型為Swift特有、無法映射到Objective-C的類型(如Character幢妄、Tuple)兔仰,則此方法、屬性無法添加dynamic修飾(會(huì)編譯錯(cuò)誤)

Swift類在Objective-C中會(huì)有模塊前綴?

轉(zhuǎn)載:http://www.chinaz.com/news/2016/0408/520403.shtml

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蕉鸳,一起剝皮案震驚了整個(gè)濱河市乎赴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌潮尝,老刑警劉巖榕吼,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異勉失,居然都是意外死亡羹蚣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門乱凿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來顽素,“玉大人,你說我怎么就攤上這事徒蟆⌒渤觯” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵段审,是天一觀的道長(zhǎng)全蝶。 經(jīng)常有香客問我,道長(zhǎng)寺枉,這世上最難降的妖魔是什么抑淫? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮姥闪,結(jié)果婚禮上始苇,老公的妹妹穿的比我還像新娘。我一直安慰自己筐喳,他們只是感情好埂蕊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疏唾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪函似。 梳的紋絲不亂的頭發(fā)上槐脏,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音撇寞,去河邊找鬼顿天。 笑死堂氯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的牌废。 我是一名探鬼主播咽白,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼鸟缕!你這毒婦竟也來了晶框?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤懂从,失蹤者是張志新(化名)和其女友劉穎授段,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體番甩,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侵贵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缘薛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窍育。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宴胧,靈堂內(nèi)的尸體忽然破棺而出漱抓,到底是詐尸還是另有隱情,我是刑警寧澤牺汤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布辽旋,位于F島的核電站,受9級(jí)特大地震影響檐迟,放射性物質(zhì)發(fā)生泄漏补胚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一追迟、第九天 我趴在偏房一處隱蔽的房頂上張望溶其。 院中可真熱鬧,春花似錦敦间、人聲如沸瓶逃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厢绝。三九已至,卻和暖如春带猴,著一層夾襖步出監(jiān)牢的瞬間昔汉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工拴清, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留靶病,地道東北人会通。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像娄周,于是被迫代替她去往敵國(guó)和親涕侈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容