iOS 了解isa-swizzling (類指針交換)

1栗精、類的結(jié)構(gòu)

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

對象和類

Objective-C 是一門面向?qū)ο蟮木幊陶Z言涝桅。
對象都是一個類的實例惊奇,對象都有一個名為 isa 的指針,指向該對象的類开仰。
類描述了一系列它的實例的特點拟枚,包括成員變量的列表,成員函數(shù)的列表等众弓。
對象都可以接受消息恩溅,而對象能夠接收的消息列表是保存在它所對應(yīng)的類中。

類和元類

類也是一個對象谓娃,是元類 (metaclass)的實列脚乡,這個類就是元類 (metaclass)。
元類保存了類方法的列表滨达。
當(dāng)一個類方法被調(diào)用時奶稠,元類會首先查找它本身是否有該類方法的實現(xiàn),如果沒有捡遍,則該元類會向它的父類查找該方法锌订,直到一直找到繼承鏈的頭。

元類 (metaclass) 也是一個對象稽莉,那么元類的 isa 指針又指向哪里呢瀑志?
為了設(shè)計上的完整,所有的元類的 isa 指針都會指向一個根元類 (root metaclass)污秆。
根元類 (root metaclass) 本身的 isa 指針指向自己劈猪,這樣就行成了一個閉環(huán)。

對象-類-元類

無法動態(tài)給對象增加成員變量

因為對象在內(nèi)存中的排布可以看成一個結(jié)構(gòu)體良拼,該結(jié)構(gòu)體的大小并不能動態(tài)變化战得。
所以無法在運行時動態(tài)給對象增加成員變量。

可以動態(tài)給對象增加方法

相對的庸推,對象的方法的定義列表是一個名為 methodLists的指針的指針常侦。
通過修改該指針指向的指針的值,就可以實現(xiàn)動態(tài)地為某一個類增加成員方法贬媒。
這也是Category實現(xiàn)的原理聋亡。同時也說明了為什么Category只可為對象增加成員方法,卻不能增加成員變量际乘。

關(guān)聯(lián)對象

通過objc_setAssociatedObject 和 objc_getAssociatedObject方法可以變相地給對象增加成員變量坡倔,但由于實現(xiàn)機(jī)制不一樣,所以并不是真正改變了對象的內(nèi)存結(jié)構(gòu)。

2罪塔、isa-swizzling

就是把當(dāng)前某個實例對象的isa指針指向一個新建造的中間類投蝉,在這個新建造的中間類上面做hook方法或者別的事情,這樣不會影響這個類的其他實例對象征堪,僅僅影響當(dāng)前的實例對象瘩缆。

.class 和 object_getClass 的區(qū)分

.class 當(dāng) target 是 Instance 則返回 Class,當(dāng) target 是 Class 則返回自身
object_getClass 返回 isa 指針的指向

動態(tài)創(chuàng)建一個 Class 的完整步驟

objc_allocateClassPair
class_addMethod
class_addIvar
objc_registerClassPair

新建中間類

3佃蚜、isa-swizzling的應(yīng)用

KVO的實現(xiàn)

當(dāng)某個類的屬性對象第一次被觀察時庸娱,系統(tǒng)就會在運行期動態(tài)地創(chuàng)建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的setter 方法爽锥。
派生類在被重寫的setter方法內(nèi)實現(xiàn)真正的通知機(jī)制
如果原類為涌韩,那么生成的派生類名為NSKVONotifying_xxx
每個類對象中都有一個isa指針指向當(dāng)前類,當(dāng)一個類對象的第一次被觀察氯夷,那么系統(tǒng)會將isa指針指向動態(tài)生成的派生類臣樱,從而在給被監(jiān)控屬性賦值時執(zhí)行的是派生類的setter方法

鍵值觀察通知依賴于NSObject 的兩個方法:willChangeValueForKey: 和 didChangevlueForKey:;
在一個被觀察屬性發(fā)生改變之前腮考, willChangeValueForKey:一定會被調(diào)用雇毫,這就會記錄舊的值。
而當(dāng)改變發(fā)生后踩蔚,didChangeValueForKey:會被調(diào)用棚放,
繼而 observeValueForKey:ofObject:change:context: 也會被調(diào)用。

KVO的這套實現(xiàn)機(jī)制中蘋果重寫了class方法馅闽,讓我們誤認(rèn)為還是使用的當(dāng)前類飘蚯,從而達(dá)到隱藏生成的派生類

aspect AOP 面向切面編程的實現(xiàn)

aspect hook實例對象方法和類方法時候也是應(yīng)用了isa-swizzling,建造了新的派生類福也,在派生類上門進(jìn)行hook局骤,這樣移除hook的時候非常方便。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末暴凑,一起剝皮案震驚了整個濱河市峦甩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌现喳,老刑警劉巖凯傲,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嗦篱,居然都是意外死亡冰单,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門灸促,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诫欠,“玉大人狮腿,你說我怎么就攤上這事∨凰撸” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵吃度,是天一觀的道長甩挫。 經(jīng)常有香客問我,道長椿每,這世上最難降的妖魔是什么伊者? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮间护,結(jié)果婚禮上亦渗,老公的妹妹穿的比我還像新娘。我一直安慰自己汁尺,他們只是感情好法精,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著痴突,像睡著了一般搂蜓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辽装,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天帮碰,我揣著相機(jī)與錄音,去河邊找鬼拾积。 笑死殉挽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拓巧。 我是一名探鬼主播斯碌,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼玲销!你這毒婦竟也來了输拇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤贤斜,失蹤者是張志新(化名)和其女友劉穎策吠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘩绒,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡猴抹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锁荔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟀给。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跋理,到底是詐尸還是另有隱情择克,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布前普,位于F島的核電站肚邢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拭卿。R本人自食惡果不足惜骡湖,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峻厚。 院中可真熱鬧响蕴,春花似錦、人聲如沸惠桃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刽射。三九已至军拟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間誓禁,已是汗流浹背懈息。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留摹恰,地道東北人辫继。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像俗慈,于是被迫代替她去往敵國和親姑宽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

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

  • 首先說明闺阱,這篇文章幾乎都是抄錄的別人的博客炮车,簡書文章,在此總結(jié)酣溃,只是為了方便記憶和以后閱讀瘦穆,如果有什么失禮的地方,...
    LiYaoPeng閱讀 4,913評論 1 14
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉赊豌,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評論 0 9
  • 一扛或、你在項目中用過 runtime 嗎?舉個例子碘饼。 a熙兔、Method Swizzling動態(tài)交換方法實現(xiàn)悲伶,實則交換...
    寫代碼的小農(nóng)民閱讀 1,365評論 0 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,092評論 1 32
  • 在上周舆声,鐵路部門推出動車組列車互聯(lián)網(wǎng)訂餐服務(wù)淮椰,也就是說,咱們可以在高鐵上點纳寂!外!賣泻拦!了毙芜!聽到這個消息簡直是感激涕零...
    會撒嬌要抱抱閱讀 390評論 0 1