Objective-C Runtime(四)isa swizzling

Runtime 4 isa swizzling

Objective-C Runtime(一)

  • 簡介
  • 對象、類的結構
    • objc_object
    • objc_class
  • 消息傳遞(Messaging)
    • objc_method
    • objc_msgSend

Objective-C Runtime(二)

  • 動態方法解析和轉發
    • 動態方法解析
    • 快速消息轉發
    • 標準消息轉發
    • 消息轉發與多繼承
    • 消息轉發與代理對象

Objective-C Runtime(三)

  • Method Swizzling
    • class_replaceMethod
    • method_setImplementation
    • method_exchangeImplementations
    • Method Swizzling 的應用
    • Method Swizzling 注意事項

Objective-C Runtime(四)

  • isa swizzling
    • 介紹
    • 應用之KVO
    • 注意

持續更新中...

介紹

對比上一篇 Runtime 3 Method Swizzling, isa swizzling 顧名思義就是把對象的 isa 指針進行替換。

根據第一篇 Runtime 1 簡介,對象、類的結構,消息傳遞,我們知道對象都有 isa 指針指向它的類,消息傳遞時也通過isa指針找到類中所對應的方法。更改對象的 isa 指針,不僅改變了它所屬于的類型,也更改了它的行為(方法)。

舉個例子:

@interface Father: NSObject
@property (nonatomic, assign) NSInteger f;
@end
@implementation Father
@end

@interface Child: Father
@property (nonatomic, assign) NSInteger c;
@end
@implementation Child
@end

然后執行:

//1
Child *child = [[Child alloc] init];
Class class = object_getClass(child); //Child
//2
NSLog(@"%ld, %ld", child.c, child.f);  //0, 0
//3
object_setClass(child, [NSObject class]);
class = object_getClass(child); //NSObject
//4
NSLog(@"%ld, %ld", child.c, child.f);  //error: -[NSObject c]: unrecognized selector sent to instance 0x60400002aaa0

上面的代碼就是將 child 對象進行 isa swizzling,具體步驟分析如下:

  1. 上面代碼創建了實例 child,它的 isa 指向 Child 類。
  2. child.cchild.f 是通過消息傳遞找到方法實現的,通過 child 的 isa 指針找到它的 Child 類,然后在 Child 類中的 method list 找 c。f 方法的查找同理,只是多了一步在 Child 類中找不到,則往它的 superclass 中找。
  3. object_setClass(child, [NSObject class]) 方法將 child 對象的 isa 指向 NSObject。
  4. 這時再進行消息傳遞時,查找的是 child 對象的 isa 指向的 NSObject 類,由于 NSObject 類沒有對應的 c 和 f 方法,最終找不到方法程序崩潰。

應用之KVO

KVO在調用存取方法之前總是調用 willChangeValueForKey: ,之后總是調用 didChangeValueForkey: 。怎么做到的呢?答案是通過 isa 混寫(isa-swizzling)。

Apple 的文檔對 KVO 實現的描述:

Automatic key-value observing is implemented using a technique called isa-swizzling.

...

When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class.

...

從Apple 的文檔可以看出:Apple 并不希望過多暴露 KVO 的實現細節。不過,要是借助 runtime 提供的方法去深入挖掘,所有被掩蓋的細節都會原形畢露:

當你觀察一個對象時,一個新的類會被動態創建。這個類繼承自該對象的原本的類,并重寫了被觀察屬性的 setter 方法。重寫的 setter 方法會負責在調用原 setter 方法之前和之后,通知所有觀察對象:值的更改。最后通過 isa 混寫(isa-swizzling) 把這個對象的 isa 指針 ( isa 指針告訴 Runtime 系統這個對象的類是什么 ) 指向這個新創建的子類,對象就神奇的變成了新創建的子類的實例。我畫了一張示意圖,如下所示:

isa_swizzling_kvo.png

然而 KVO 在實現中使用了 isa-swizzling 的確不是很容易發現:Apple 還重寫了-class方法并返回原來的類。企圖欺騙我們:這個類沒有變,就是原本那個類。。。如下:

Father *father = [[Father alloc] init];
[father addObserver:self forKeyPath:@"f" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"%@", object_getClass(father)); //NSKVONotifying_Father
NSLog(@"%@", father.class); //Father

假設“被監聽的對象”的類對象是 MYClass ,有時候我們能看到對 NSKVONotifying_MYClass 的引用而不是對 MYClass 的引用。借此我們得以知道 Apple 使用了 isa 混寫(isa-swizzling)。具體探究過程可參考 這篇博文 。

由下面執行過程可知,通過KVO生成的中間類繼承原來的類:

Class kvoClass = object_getClass(father);
Class kvoSuperClass = class_getSuperclass(kvoClass);
NSLog(@"%@", kvoSuperClass); //Father

注意

isa-swizzling 改變了對象說屬類型,因此更改范圍比 method-swizzling 范圍更廣,使用時要更加注意。

runtime 極其尖銳,選擇使用 runtime 時要清楚每一步的真正原理。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380