Runtime 方法调用本质(消息发送、动态方法解析、消息转发)二

动态方法解析、消息转发

如果方法实现(imp)没有找到会尝试一次动态方法解析,源码如

if (resolver  &&  !triedResolver) {
        runtimeLock.unlockRead();
        _class_resolveMethod(cls, sel, inst);
        runtimeLock.read();
        // Don't cache the result; we don't hold the lock so it may have 
        // changed already. Re-do the search from scratch instead.
        triedResolver = YES;
        goto retry;
    }

动态方法解析调用 "_class_resolveMethod" 是实例方法调用 进入 "_class_resolveInstanceMethod(cls, sel, inst);", 类方法调用" _class_resolveClassMethod(cls, sel, inst);" 方法实现如图

void _class_resolveMethod(Class cls, SEL sel, id inst)
{
    if (! cls->isMetaClass()) {
        // try [cls resolveInstanceMethod:sel]
        _class_resolveInstanceMethod(cls, sel, inst);
    } 
    else {
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        _class_resolveClassMethod(cls, sel, inst);
        if (!lookUpImpOrNil(cls, sel, inst, 
                            NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 
        {
            _class_resolveInstanceMethod(cls, sel, inst);
        }
    }
}

尝试一次动态方法解析没有找到会调用消息转发,到此动态方法解析完成。没找到之后进行消息转发并将查找的IMP添加到缓存里,源码如

    imp = (IMP)_objc_msgForward_impcache;
    cache_fill(cls, sel, imp, inst);

消息转发调用方法_objc_msgForward_impcache 回到汇编中,源码如

    STATIC_ENTRY __objc_msgForward_impcache

    MESSENGER_START
    nop
    MESSENGER_END_SLOW

    // No stret specialization.
    b   __objc_msgForward

    END_ENTRY __objc_msgForward_impcache

    
    ENTRY __objc_msgForward

    adrp    x17, __objc_forward_handler@PAGE
    ldr x17, [x17, __objc_forward_handler@PAGEOFF]
    br  x17
    
    END_ENTRY __objc_msgForward

进入方法首先跳转 __objc_msgForward 方法, 在跳转 __objc_forward_handler回到C方法 源码如

#if !__OBJC2__

// Default forward handler (nil) goes to forward:: dispatch.
void *_objc_forward_handler = nil;
void *_objc_forward_stret_handler = nil;

#else

// Default forward handler halts the process.
__attribute__((noreturn)) void 
objc_defaultForwardHandler(id self, SEL sel)
{
    _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
                "(no message forward handler is installed)", 
                class_isMetaClass(object_getClass(self)) ? '+' : '-', 
                object_getClassName(self), sel_getName(sel), self);
}
void *_objc_forward_handler = (void*)objc_defaultForwardHandler;

方法 _objc_forward_handler 实际是一个C方法,系统给出了一个默认实现,到这源码结束。消息转发调用过程可以通过 runTime消息打印API来实现

extern void instrumentObjcMessageSends(BOOL);

消息转发会有两种实现, 一种是

- (id)forwardingTargetForSelector:(SEL)aSelector {
     // 可以在此方法里进行动态添加处理
    return [super forwardingTargetForSelector:aSelector];
}

另一种是

/// 方法名注册
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector  {
    return [super methodSignatureForSelector:aSelector];
}
/// 在此方法里处理响应
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    
}

第二种方法比较灵活,可以进行hook等操作。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容