Objective-C 的動態特性源於其獨特的對象模型與 Runtime 系統。本文從結構體定義出發,層層剖析實例對象、類對象、元類對象的 isa 指針鏈、消息發送流程、動態方法解析、完整消息轉發、方法緩存優化、關聯對象實現,並給出調試技巧與實戰應用模式。
// objc.h 簡化版
typedef struct objc_object *id;
typedef struct objc_class *Class;
struct objc_object {
Class isa; // 實例對象指向其類對象
};
struct objc_class {
Class isa; // 類對象指向其元類對象
Class superclass; // 父類指針
const char *name; // 類名
// ... 以下為舊版 ABI 字段,現代 Runtime 通過 bits 存儲
struct objc_ivar_list *ivars; // 實例變量列表
struct objc_method_list **methodLists; // 方法列表
struct objc_cache *cache; // 方法緩存
struct objc_protocol_list *protocols; // 協議列表
};
實例對象 (instance)
isa ──→ 類對象 (Class Object) [存儲實例方法、實例變量佈局]
isa ──→ 元類對象 (Meta Class) [存儲類方法]
isa ──→ 基類元類 (NSObject Meta) → isa 指向自身 (閉環)
superclass ──→ 父類對象
superclass ──→ ... → NSObject 類對象 → superclass = nil
id 類型,內存佈局首字段為 isa,隨後是實例變量。// 編譯器將 [receiver message] 轉為:
id objc_msgSend(id self, SEL op, ...);
// objc_msgSend 核心邏輯(偽代碼)
id objc_msgSend(id self, SEL op, ...) {
Class cls = self->isa;
// 1. 快速路徑:緩存查找
IMP imp = cache_get(cls->cache, op);
if (imp) return imp(self, op, ...);
// 2. 慢速路徑:方法列表遍歷
imp = class_getMethodImplementation(cls, op);
if (imp) {
cache_add(cls->cache, op, imp); // 填充緩存
return imp(self, op, ...);
}
// 3. 向上查找父類鏈
for (Class super = cls->superclass; super; super = super->superclass) {
imp = class_getMethodImplementation(super, op);
if (imp) {
cache_add(cls->cache, op, imp);
return imp(self, op, ...);
}
}
// 4. 消息轉發入口
return objc_msgSend_forward(self, op, ...);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel / resolveClassMethod:class_addMethod),返回 YES 重新進入發送流程。- (id)forwardingTargetForSelector:(SEL)sel- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel + - (void)forwardInvocation:(NSInvocation *)inv// 示例:動態添加屬性存取器
+ (BOOL)resolveInstanceMethod:(SEL)sel {
const char *name = sel_getName(sel);
if (strncmp(name, "set", 3) == 0 || strncmp(name, "get", 3) == 0) {
class_addMethod(self, sel, (IMP)dynamicAccessor, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
bucket_t 數組),鍵為 SEL,值為 IMP。mask = allocated - 1; index = (sel >> 2) & mask; 開放寻址法解決衝突。objc_msgSend 先查緩存,命中率極高(>95%)。// API
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void *key);
void objc_removeAssociatedObjects(id object);
// 策略枚舉
typedef enum {
OBJC_ASSOCIATION_ASSIGN = 0, // 弱引用
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 強引用,非原子
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, // 複製,非原子
OBJC_ASSOCIATION_RETAIN = 01401, // 強引用,原子
OBJC_ASSOCIATION_COPY = 01403 // 複製,原子
} objc_AssociationPolicy;
// 實現原理:全局哈希表 (AssociationsHashMap),鍵 = 對象地址 + key,值 = ObjcAssociation(value, policy)
// 對象 dealloc 時,Runtime 遍歷關聯表釋放/複製對應 value。
應用場景:Category 中添加存儲屬性、KVO 輔助、運行時擴展系統類行為。
| 需求 | 命令/代碼 |
|---|---|
| 打印對象 isa 類名 | po (id)[obj class] / po object_getClass(obj) |
| 列出類所有方法 | po [MyClass methodList] (需分類) / class_copyMethodList |
| 動態添加方法 | class_addMethod(cls, @selector(newMethod), (IMP)func, "v@:") |
| 交換方法 | method_exchangeImplementations(m1, m2) (Method Swizzling) |
| 查看消息轉發調用棧 | 在 forwardInvocation: 設置斷點,bt |
Objective-C Runtime 以 isa 指針鏈構建對象模型、雙層查找(緩存+列表)加速消息發送、三級轉發機制保證動態性、關聯對象突破編譯時佈局限制。深入理解這些機制,是掌握 KVO/KVC、Method Swizzling、動態代理、熱修復、組件化解耦等高級技術的前提。