iOS - 消息机制

1. 基本数据结构

objectivec 复制代码
// 方法结构
struct method_t {
    SEL name;       // 方法名
    const char *types;  // 类型编码
    IMP imp;       // 方法实现
};

// 类结构
struct objc_class {
    Class isa;
    Class superclass;
    cache_t cache;        // 方法缓存
    class_data_bits_t bits;  // 类的方法、属性等信息
};

// 方法缓存
struct cache_t {
    struct bucket_t *_buckets;  // 散列表
    mask_t _mask;              // 容量掩码
    mask_t _occupied;          // 已使用数量
};

2. 消息发送流程

2.1 基本流程

objectivec 复制代码
// 消息发送入口
id objc_msgSend(id self, SEL _cmd, ...) {
    if (!self) return nil;
    
    // 1. 查找方法缓存
    IMP imp = cache_getImp(self->isa, _cmd);
    if (imp) return imp(self, _cmd, ...);
    
    // 2. 完整查找流程
    return _objc_msgSend_uncached(self, _cmd, ...);
}

2.2 方法查找

objectivec 复制代码
IMP lookUpImpOrForward(id obj, SEL sel) {
    Class cls = obj->getIsa();
    
    // 1. 查找当前类的方法
    Method method = class_getInstanceMethod(cls, sel);
    if (method) {
        // 加入缓存
        cache_fill(cls, sel, method->imp);
        return method->imp;
    }
    
    // 2. 查找父类方法
    for (Class tcls = cls->superclass; tcls; tcls = tcls->superclass) {
        method = class_getInstanceMethod(tcls, sel);
        if (method) {
            cache_fill(cls, sel, method->imp);
            return method->imp;
        }
    }
    
    // 3. 动态方法解析
    if (resolveInstanceMethod(cls, sel)) {
        return lookUpImpOrForward(obj, sel);
    }
    
    // 4. 消息转发
    return _objc_msgForward;
}

3. 方法缓存机制

3.1 缓存结构

objectivec 复制代码
struct cache_t {
    // 缓存桶
    struct bucket_t {
        SEL _sel;   // 方法名
        IMP _imp;   // 方法实现
    } *_buckets;
    
    // 查找方法
    IMP imp(SEL sel) {
        bucket_t *b = buckets();
        mask_t m = mask();
        mask_t begin = cache_hash(sel, m);
        mask_t i = begin;
        do {
            if (b[i].sel() == sel) {
                return b[i].imp();
            }
        } while ((i = cache_next(i, m)) != begin);
        return nil;
    }
};

3.2 缓存优化

objectivec 复制代码
// 缓存哈希算法
static inline mask_t cache_hash(SEL sel, mask_t mask) {
    return (mask_t)(uintptr_t)sel & mask;
}

// 缓存扩容
void cache_t::expand() {
    uint32_t oldCapacity = capacity();
    uint32_t newCapacity = oldCapacity ? oldCapacity * 2 : INIT_CACHE_SIZE;
    
    if (newCapacity > MAX_CACHE_SIZE) {
        newCapacity = MAX_CACHE_SIZE;
    }
    
    reallocate(oldCapacity, newCapacity);
}

4. 消息转发机制

4.1 动态方法解析

objectivec 复制代码
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(someMethod:)) {
        class_addMethod(self,
                       sel,
                       (IMP)dynamicMethodIMP,
                       "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

4.2 快速转发

objectivec 复制代码
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(someMethod:)) {
        return alternateObject;  // 转发给其他对象
    }
    return [super forwardingTargetForSelector:aSelector];
}

4.3 完整转发

objectivec 复制代码
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(someMethod:)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([alternateObject respondsToSelector:
         [anInvocation selector]]) {
        [anInvocation invokeWithTarget:alternateObject];
    } else {
        [super forwardInvocation:anInvocation];
    }
}

5. 性能优化

5.1 方法缓存

objectivec 复制代码
// 缓存命中检查
static ALWAYS_INLINE IMP cache_getImp(Class cls, SEL sel) {
    cache_key_t key = cache_key(sel);
    bucket_t *buckets = cls->cache.buckets();
    mask_t mask = cls->cache.mask();
    
    bucket_t *bucket = &buckets[key & mask];
    if (bucket->key() == key) {
        return bucket->imp();
    }
    return nil;
}

5.2 方法内联

objectivec 复制代码
// 编译器优化
static ALWAYS_INLINE id 
objc_msgSendSuper2(struct objc_super2 *super, SEL op, ...) {
    return ((id (*)(struct objc_super2 *, SEL, ...))objc_msgSendSuper2_fixup)(super, op, ...);
}

6. 特殊情况处理

6.1 nil 消息

objectivec 复制代码
if (!self) return nil;  // 发送给 nil 的消息返回 nil

6.2 Tagged Pointer

objectivec 复制代码
if (objc_isTaggedPointer(obj)) {
    // 特殊处理 Tagged Pointer
    return objc_msgSend_tagged(obj, sel, ...);
}

7. 线程安全

7.1 缓存更新

objectivec 复制代码
static void cache_fill(Class cls, SEL sel, IMP imp) {
    cache_t *cache = &cls->cache;
    
    cache->mutex.lock();
    // 更新缓存
    cache->insert(sel, imp);
    cache->mutex.unlock();
}

7.2 方法添加

objectivec 复制代码
static IMP addMethod(Class cls, SEL name, IMP imp, const char *types) {
    mutex_locker_t lock(runtimeLock);
    
    IMP result = nil;
    if (addMethodNoLock(cls, name, imp, types, &result)) {
        // 更新方法缓存
        flushCaches(cls);
    }
    
    return result;
}

这个消息机制设计的关键点:

  1. 高效的方法查找
  2. 灵活的消息转发
  3. 优秀的缓存策略
  4. 完善的线程安全
  5. 特殊情况的处理

这些特性使得 Objective-C 的消息机制既灵活又高效。

相关推荐
iOS阿玮11 小时前
聊聊正式接单第一天的感悟,以及Appstore合规化的看法。
ios
张二三12 小时前
flutter 开发笔记(九):原生桥接
android·flutter·ios
ii_best13 小时前
ios越狱脚本巨魔商店安装教程
ios
Batac_蝠猫14 小时前
iOS - 线程与AutoreleasePoolPage
ios
健忘已成殇17 小时前
iOS 本地新项目上传git仓库,并使用sourceTree管理
git·ios·xcode·cocoapods
ii_best17 小时前
ios脚本巨魔商店多巴胺越狱基本操作教程
ios
Batac_蝠猫18 小时前
iOS - AutoreleasePool
ios
长风清留扬21 小时前
小程序开发-页面事件之上拉触底实战案例
前端·javascript·css·ios·微信小程序·小程序·html
OkeyProxy21 小时前
怎麼在iPhone iOS(Wi-Fi/蜂窩數據)上查找IP地址?
ios·代理模式·proxy模式·ip地址·代理ip