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

Objective-C Runtime 機制深度解析:消息分發、類結構與 Method Swizzling

     編輯:關於C語言

Objective-C Runtime 機制深度解析:消息分發、類結構與 Method Swizzling

Objective-C 是一門高度動態的語言,將大量編譯期、鏈接期決策推遲到執行期。這套由 C 與組合語言編寫的 Runtime 庫,是 OC 物件模型的核心引擎。本文深入剖析消息機制、類/元類結構、方法快取、動態解析與 Method Swizzling 等核心機制。

核心觀念:從函數呼叫到消息發送

  • C 函數呼叫:編譯期靜態綁定,編譯完成即確定呼叫位址,無歧義。
  • OC 方法呼叫:[obj makeText] 編譯為 objc_msgSend(obj, @selector(makeText))。執行期動態查找,編譯期僅檢查聲明存在性。

這意味著:

  1. 可向任何物件發送任何消息(即使未實現),僅在執行期決定如何處理。
  2. 消息可轉發、攔截、動態新增/交換實現。
  3. Runtime 如同一個微型作業系統,管理類、物件、方法的生命週期與關係。

物件與類的記憶體佈局

實例物件

// NSObject 定義
@interface NSObject {
    Class isa;  // 指向其類物件
}
```

類物件 (Class) 結構

struct objc_class {
    Class isa;                    // 指向元類
    Class super_class;            // 父類
    const char *name;             // 類名
    long version;                 // 版本資訊
    long info;                    // 標識位 (CLS_CLASS / CLS_META)
    long instance_size;           // 實例大小
    struct objc_ivar_list *ivars; // 成員變量列表
    struct objc_method_list **methodLists; // 方法列表
    struct objc_cache *cache;     // 方法快取
    struct objc_protocol_list *protocols;  // 協議列表
};

關鍵指標關係圖解

  • 實例 isa → 類物件 (存放實例方法 -、實例變數)
  • 類物件 isa → 元類物件 (存放類方法 +、靜態變數)
  • 元類 isa → 根元類 (Root Meta Class)
  • 根元類 isa → 指向自己
  • super_class 鏈向父類,直到根類

這構成了雙層平行繼承體系:實例鏈與類/元類鏈。

消息發送與查找流程

id objc_msgSend(id self, SEL op, ...) {
    // 1. 從 self->isa 取得類物件
    Class cls = self->isa;

    // 2. 先查 cache (最近使用方法)
    IMP imp = cache_get(cls->cache, op);
    if (imp) return imp(self, op, ...);

    // 3. 再查 methodLists
    imp = methodList_find(cls->methodLists, op);
    if (imp) {
        cache_add(cls->cache, op, imp);
        return imp(self, op, ...);
    }

    // 4. 遞迴查 super_class
    cls = cls->super_class;
    // ... 重複 2-3 步驟

    // 5. 找不到 → 進入消息轉發流程
    return _objc_msgForward(self, op, ...);
}

關鍵資料結構

  • SEL (Selector):方法選擇器,本質是 const char* 指向唯一字串。同名方法共用一個 SEL,故 OC 不支援多載。
  • IMP (Implementation):方法實際執行代碼的函數指標,簽名 id (*IMP)(id, SEL, ...)。
  • Method:封裝 SEL、IMP、型別編碼的結構體。
  • Cache:雜湊表,Key=SEL,Value=IMP,加速熱點方法查找。

動態特性三大支柱

  1. 動態類型:執行期決定物件類型 (id、isKindOfClass:)
  2. 動態繫結:執行期決定呼叫哪個實現 (objc_msgSend)
  3. 動態載入:執行期載入新類/分類 (dlopen、NSBundle)

Method Swizzling:運行期交換方法實現

利用 SEL→IMP 映射在執行期可變的特性,交換兩個方法的 IMP,實現「不繼承重寫、仍能呼叫原實現」的效果。

// 典型用法:在 Category 中交換系統方法
#import <objc/runtime.h>

@implementation UIViewController (Swizzling)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = [self class];
        SEL original = @selector(viewWillAppear:);
        SEL swizzled = @selector(my_viewWillAppear:);
        Method origMethod = class_getInstanceMethod(cls, original);
        Method swizzledMethod = class_getInstanceMethod(cls, swizzled);

        // 1. 確保原方法有實現(若無則添加)
        BOOL added = class_addMethod(cls, original,
            method_getImplementation(swizzledMethod),
            method_getTypeEncoding(swizzledMethod));
        if (added) {
            class_replaceMethod(cls, swizzled,
                method_getImplementation(origMethod),
                method_getTypeEncoding(origMethod));
        } else {
            // 2. 直接交換 IMP
            method_exchangeImplementations(origMethod, swizzledMethod);
        }
    });
}

- (void)my_viewWillAppear:(BOOL)animated {
    // 執行前置邏輯
    NSLog(@"Before viewWillAppear");
    // 呼叫原實現(實際上調用的是 swizzled 後的 original)
    [self my_viewWillAppear:animated];
    // 執行後置邏輯
    NSLog(@"After viewWillAppear");
}

@end

Swizzling 注意事項

  • 務必在 +load 中執行(保證單次、早期執行),避免競態條件。
  • 使用 dispatch_once 確保線程安全。
  • 交換前檢查方法是否存在,避免 Crash。
  • 保持方法簽名一致,否則參數傳遞錯誤導致未定義行為。
  • 慎用於系統類,可能違反 App Store 審核指引或導致系統行為異常。

Runtime 實際應用場景

深入理解 Objective-C Runtime,不僅能解決疑難雜症、實現高階框架功能,更能從本質上洞悉物件導向語言的動態本質。建議配合 objc/runtime.h 頭文件與 Apple 官方文檔《Objective-C Runtime Programming Guide》進行實作演練。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景關鍵 API說明
關聯物件objc_setAssociatedObject / objc_getAssociatedObject在 Category 中模擬屬性
動態新增方法class_addMethod, resolveInstanceMethod:實現 KVO、Core Data 動態存取
方法交換method_exchangeImplementationsAOP、埋點、熱修復
遍歷屬性/方法/協議class_copyPropertyList 等自動序列化、字典轉模型
動態建立類objc_allocateClassPair, objc_registerClassPairKVO 實現、Proxy 模式