iOS 动态方法解析知识点补充

203 阅读1分钟

本文以此文章为基础, 做一些细节的补充.

抛出问题

在慢速流程中, 方法要想被成功调用, 就必须返回对应的IMP, 也就是以下方法得有返回值才行.

IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver)

原文里, 作者重写了resolveInstanceMethod方法, 并为未实现的方法动态添加了doInstead方法, 代码片段如下. 但添加完新方法之后, 如何根据SEL获得新的IMP的流程却没有提到.

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(doInstanceNoImplementation)) {
        NSLog(@"——————————找不到%@-%@方法,崩溃了——————————", self, NSStringFromSelector(sel));
        IMP insteadIMP = class_getMethodImplementation(self, @selector(doInstead));
        Method insteadMethod = class_getInstanceMethod(self, @selector(doInstead));
        const char *instead = method_getTypeEncoding(insteadMethod);
        /// 此处新方法的SEL也是传进来的sel, 所以可以通过遍历method list并比较name(SEL)来获取对应的IMP
        return class_addMethod(self, sel, insteadIMP, instead);
    }
    
    return NO;
}

其实很简单, 关键就是getMethodNoSuper_nolock这个c函数.

寻找答案

整体流程如下: _class_resolveMethod --> _class_resolveInstanceMethod or _class_resolveClassMethod --> 动态添加新的方法实现 --> 返回到 lookUpImpOrForward 方法并执行goto retry; --> 触发getMethodNoSuper_nolock(cls, sel); --> 方法内部会获取并遍历cls的method list, 再将method的name(也就是SEL)和传入的sel 参数做匹配, 如果有匹配的就返回对应的method. --> 最后根据返回的method获取到IMP, log_and_fill_cache 完成了动态决议流程.

代码参考

相关的代码太长, 这里就不贴了. 原文里都有, 感兴趣的可以参考原文或者去Apple官网看看