动态方法解析

Dynamic Method Resolution

我知道如果在 class 或其超 classes 中找不到方法的实现,运行时会提供执行消息的机会。它首先将消息 + (BOOL)resolveInstanceMethod:(SEL)name 发送到对象的 class:此方法允许您在运行时将方法添加到 class:如果此消息 returns是的,这意味着它可以从 + (BOOL)resolveInstanceMethod:(SEL)name 重新发送 message.i 尝试到 return 否,我认为这将使 -(id)forwardingTargetForSelector:(SEL)aSelector 被调用(并且 dynamicMethodIMP 不会被调用被调用),但仍会调用 dynamicMethodIMP,因为 return 值为 YES。 Apple Doc 说

If the method returns NO, the Objective-C runtime will pass control to the method forwarding mechanism(https://developer.apple.com/library/mac/releasenotes/Foundation/RN-FoundationOlderNotes/)

return YES 和 return No 有什么区别 + (BOOL)resolveInstanceMethod:(SEL)name。 一段这样的示例代码:

`void dynamicMethodIMP(id self, SEL _cmd) {
    NSLog(@"%@ has added", NSStringFromSelector(_cmd));
}
+(BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(mustHas)) {
        class_addMethod([self class], sel, (IMP) dynamicMethodIMP, "v@:");
        return NO;
    }
    return [super resolveInstanceMethod:sel];
}` 
[obj mustHas];

您正在阅读的文档来自 10.5 发行说明,但该特定声明不属于 current documentation

class_resolveInstanceMethod() 的实现实际上忽略了您的 return 值。它只是检查您是否已实现 +resolveInstanceMethod,如果已实现则调用它,然后查找原始选择器(只是为了缓存结果)。您的 return 值唯一重要的时候是调试运行时。

无需猜测消息转发的工作原理。这都是开源的。这是调用 +resolveInstanceMethod (runtime/objc-class.mm) 的函数:

/***********************************************************************
* _class_resolveInstanceMethod
* Call +resolveInstanceMethod, looking for a method to be added to class cls.
* cls may be a metaclass or a non-meta class.
* Does not check if the method already exists.
**********************************************************************/
static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst)
{
    if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, 
                         NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) 
    {
        // Resolver not implemented.
        return;
    }

    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    BOOL resolved = msg(cls, SEL_resolveInstanceMethod, sel);

    // Cache the result (good or bad) so the resolver doesn't fire next time.
    // +resolveInstanceMethod adds to self a.k.a. cls
    IMP imp = lookUpImpOrNil(cls, sel, inst, 
                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);

    if (resolved  &&  PrintResolving) {
        if (imp) {
            _objc_inform("RESOLVE: method %c[%s %s] "
                         "dynamically resolved to %p", 
                         cls->isMetaClass() ? '+' : '-', 
                         cls->nameForLogging(), sel_getName(sel), imp);
        }
        else {
            // Method resolver didn't add anything?
            _objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
                         ", but no new implementation of %c[%s %s] was found",
                         cls->nameForLogging(), sel_getName(sel), 
                         cls->isMetaClass() ? '+' : '-', 
                         cls->nameForLogging(), sel_getName(sel));
        }
    }
}