OC底层原理11 - 动态方法解析

2021-01-29  本文已影响0人  卡布奇诺_95d2

动态方法解析

之前在分析objc_msgSend的时候,当慢速查找和快速查找都未找到SEL时,会根据当前设置的条件(behavior & LOOKUP_RESOLVER)选择是否进行动态方法解析,接下来我们就来探索一下动态方法解析的源码

resolveMethod_locked 源码

static NEVER_INLINE IMP
resolveMethod_locked(id inst, SEL sel, Class cls, int behavior)
{
    runtimeLock.assertLocked();
    ASSERT(cls->isRealized());

    runtimeLock.unlock();

    //判断当前是否是元类,如果非元类,则调用实例方法的动态方法解析
    if (! cls->isMetaClass()) {
        // try [cls resolveInstanceMethod:sel]
        resolveInstanceMethod(inst, sel, cls);
    } 
    else {
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        //如果是元类,是调用对象方法的动态方法解析
        resolveClassMethod(inst, sel, cls);
        if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
            resolveInstanceMethod(inst, sel, cls);
        }
    }

    // chances are that calling the resolver have populated the cache
    // so attempt using it
    // 重新在当前类中查找SEL方法
    return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);
}

从以上代码看到,主要分为两种可能:1、当前类为非元类,则调用resolveInstanceMethod方法进行动态解析;2、当前类为元类,则调用resolveClassMethod方法进行动态解析。

resolveInstanceMethod

resolveInstanceMethod源码

static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
    runtimeLock.assertUnlocked();
    ASSERT(cls->isRealized());
    SEL resolve_sel = @selector(resolveInstanceMethod:);

    //在当前类的缓存列表中查找 resolveInstanceMethod: 方法
    // 查找 resolveInstanceMethod: 方法仍然采用快速查找和慢速查找的流程
    if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
        // Resolver not implemented.
        return;
    }

    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    //执行 [cls resolveInstanceMethod:sel]方法
    bool resolved = msg(cls, resolve_sel, sel);

    // Cache the result (good or bad) so the resolver doesn't fire next time.
    // +resolveInstanceMethod adds to self a.k.a. cls
    //重新按快速查找,慢速查找的方法,查找SEL
    IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
}

resolveInstanceMethod 说明

resolveClassMethod

resolveClassMethod源码

static void resolveClassMethod(id inst, SEL sel, Class cls)
{
    runtimeLock.assertUnlocked();
    ASSERT(cls->isRealized());
    ASSERT(cls->isMetaClass());

    //查找类中是否有resolveClassMethod:实现
    if (!lookUpImpOrNilTryCache(inst, @selector(resolveClassMethod:), cls)) {
        // Resolver not implemented.
        return;
    }

    Class nonmeta;
    {
        mutex_locker_t lock(runtimeLock);
        nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
        // +initialize path should have realized nonmeta already
        if (!nonmeta->isRealized()) {
            _objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
                        nonmeta->nameForLogging(), nonmeta);
        }
    }
    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);

    // Cache the result (good or bad) so the resolver doesn't fire next time.
    // +resolveClassMethod adds to self->ISA() a.k.a. cls
    IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
}

说明

总结

resolveMethod_locked 总结

+(BOOL)resolveInstanceMethod:(SEL)sel {
//    NSLog(@"动态添加%@方法", NSStringFromSelector(sel));
    if (sel == NSSelectorFromString(@"say666")) {
        NSLog(@"%@ 来了", NSStringFromSelector(sel));
        //获取sayMaster方法的imp
        IMP imp = class_getMethodImplementation(self, NSSelectorFromString(@"instanceMethod"));
        //获取sayMaster的实例方法
        Method sayMethod  = class_getInstanceMethod(self, NSSelectorFromString(@"instanceMethod"));
        //获取sayMaster的丰富签名
        const char *type = method_getTypeEncoding(sayMethod);
        //将sel的实现指向sayMaster
        class_addMethod(self, sel, imp, type);
        return YES;
    }
    else if (sel == NSSelectorFromString(@"sayNB")) {
        NSLog(@"%@ 来了", NSStringFromSelector(sel));
        //获取sayMaster方法的imp
        IMP imp = class_getMethodImplementation(objc_getMetaClass("HQPerson"), NSSelectorFromString(@"classMethod"));
        //获取sayMaster的实例方法
        Method sayMethod  = class_getInstanceMethod(objc_getMetaClass("HQPerson"), NSSelectorFromString(@"classMethod"));
        //获取sayMaster的丰富签名
        const char *type = method_getTypeEncoding(sayMethod);
        //将sel的实现指向sayMaster
        class_addMethod(objc_getMetaClass("HQPerson"), sel, imp, type);
        return YES;
    }
    return NO;
}
上一篇 下一篇

猜你喜欢

热点阅读