首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C Runtime 深度解析(一):消息機制、isa/元類、緩存查找、動態轉發全流程

     編輯:關於C語言

Objective-C Runtime 深度解析(一):消息機制全流程

Runtime 是 Objective-C 動態特性的核心。面試大廠必問,實戰 Swizzling、動態屬性、協議實現皆建立於此。本文從源碼級視角剖析 objc_msgSend、isa/元類體系、方法緩存、消息轉發三階段。

1. 消息發送入口:objc_msgSend

// 編譯器將 [obj makeText] 轉為:
objc_msgSend(obj, @selector(makeText));

彙編級實現 (arm64 簡化):

objc_msgSend:
    // 1. 取 receiver 的 isa
    ldr x13, [x0]           // x13 = obj->isa
    // 2. 從 isa 取類對象 (非 metaclass)
    and x13, x13, #0x7FFFFFFFFFF8  // 去除 tagged pointer 位
    // 3. 查找緩存
    ldr x12, [x13, #CACHE_OFFSET]
    // ... cache lookup ...
    // 4. 緩存未命中 → __objc_msgSend_uncached
    b __objc_msgSend_uncached

2. 類對象結構體 (objc_class)

struct objc_class {
    Class isa;                          // → metaclass
    Class super_class;                  // → 父類
    const char *name;                   // 類名
    long version, info;                 // 版本/標志
    long instance_size;                 // 實例大小
    struct objc_ivar_list *ivars;       // 實例變量列表
    struct objc_method_list **methodLists; // 方法列表數組
    struct objc_cache *cache;           // 方法緩存 (SEL→IMP)
    struct objc_protocol_list *protocols;
};

3. isa / 元類體系圖解

實例 obj          → isa → 類對象 (Class)          → 存儲實例方法、實例變量
類對象 (Class)    → isa → 元類 (Metaclass)       → 存儲類方法、類變量
元類 (Metaclass)  → isa → 根元類 (NSObject meta) → isa 指向自身
根類 (NSObject)   → super_class = nil

關鍵點:

  • 所有類對象是 objc_class 結構體,元類也是同一結構體,區別在 info 位標志 (CLS_CLASS vs CLS_META)。
  • 實例 isa 指向類對象;類對象 isa 指向元類;元類 isa 最終指向根元類,根元類 isa 指向自身。
  • 方法查找順序:receiver->isa->cache → methodLists → super_class→cache → ...

4. SEL (選擇器)

  • 類型:typedef struct objc_selector *SEL; 本質是 const char* 唯一化後的指針。
  • 生成:@selector(methodName) 編譯期生成,同名方法同一 SEL (不區分參數類型)。
  • 緩存鍵:SEL 經哈希映射到緩存桶,O(1) 查找 IMP。

5. 消息查找完整流程

  1. receiver->isa 獲取類對象
  2. 類對象 cache 中按 SEL 查找 IMP → 命中直接跳轉
  3. 遍歷 methodLists (按類別編譯順序) 查找 SEL → 找到則填入 cache 並跳轉
  4. super_class 遞歸向上查找,直到根類
  5. 全部未命中 → 進入消息轉發

6. 消息轉發三階段

階段方法用途返回
1. 動態解析+resolveInstanceMethod:
+resolveClassMethod:
運行時動態添加方法實現 (如 class_addMethod)YES 重新嘗試發送
2. 備用接收者-forwardingTargetForSelector:將消息轉發給其他對象 (零開銷)目標對象或 nil
3. 完整轉發-methodSignatureForSelector:
-forwardInvocation:
構造 NSInvocation 任意處理 (修改參數、返回值、延遲執行)無

7. 特殊情況

  • nil 接收者:objc_msgSend(nil, sel) 直接返回 0/nil/零結構體,無崩潰。
  • super 調用:編譯器生成 objc_msgSendSuper(&super_struct, sel),從 super_class 開始查找。
  • Tagged Pointer:小整數/小字符串直接編碼在指針中,無 isa,Runtime 特殊處理。

8. 實戰:Method Swizzling

Method m1 = class_getInstanceMethod(cls, @selector(original));
Method m2 = class_getInstanceMethod(cls, @selector(swizzled));
method_exchangeImplementations(m1, m2);  // 交換 IMP

原理:直接修改 methodLists 中的 IMP 指針,緩存會在下次查找時自動更新。

小結

Objective-C 消息機制 = isa 指針鏈 + 緩存哈希表 + 線性列表掃描 + 三階段轉發。理解此流程,即可掌握 Swizzling、動態添加方法、協議轉發、性能優化 (預熱緩存) 等高階技術。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved