消息查找流程浅析学习

2019-12-31  本文已影响0人  竹屋听雨

⤵️ 💝 this is a very important image!💝⤵️

isa流程图.png
         LGStudent *student = [[LGStudent alloc] init];
        // 对象方法测试
        // 对象的实例方法 - 自己有
         [student sayHello];
        // 对象的实例方法 - 自己没有 - 找父类的
         [student sayNB];
        // 对象的实例方法 - 自己没有 - 父类没有 - 找父类的父类 - NSObject
         [student sayMaster];
如果 调用了自己没有 父类也没有 父类的父类也没找到 那怎么办:? 只有崩溃了。say goodbey😁
//        [student performSelector:@selector(saySomething)];

打印结果:
2019-12-30 17:04:30.031404+0800 LGTest[19305:1050998] -[LGStudent sayHello]
2019-12-30 17:04:30.032028+0800 LGTest[19305:1050998] -[LGPerson sayNB]
2019-12-30 17:04:30.032185+0800 LGTest[19305:1050998] -[NSObject(LG) sayMaster]

// 类方法 - 自己有
   [LGStudent sayObjc];
// 类方法 - 自己没有 - 父类有
   [LGStudent sayHappay];
// 类方法 - 自己没有 - 找父类的父类 - NSObject
   [LGStudent sayEasy];
 // 类方法- 自己没有 -父类没有 - 找父类的父类 -> NSObject 也没有 - 奔溃
//         [LGStudent performSelector:@selector(sayGoodbey)];
 
打印结果
2019-12-30 17:20:18.825145+0800 LGTest[19411:1057907] +[LGStudent sayObjc]
2019-12-30 17:20:18.825882+0800 LGTest[19411:1057907] +[LGPerson sayHappay]
2019-12-30 17:20:18.825983+0800 LGTest[19411:1057907] +[NSObject(LG) sayEasy]


Mark 有点平淡无奇:
233233
// 类方法- 自己没有 - 父类没有 - 找父类的父类-> NSObject 也没有 - 但是有对象实例方法
[LGStudent sayMaster];
2019-12-30 17:24:13.253013+0800 LGTest[19454:1060098] -[NSObject(LG) sayMaster]
调用流程:
-LGStudent :(instanceOfSubclass) --> LGPerson :Subclass (class)-->NSObject: Subclass(meta) -->Superclass(meta) -->RootClass(meta) -->RootClass(class)【NSObject】
根源类的父类 -》NSObject

这个地方如果去调用sayHello 就会发生美妙的瞬间了🧶原因就是在isa的走位图。


@interface LGPerson : NSObject
- (void)sayNB;
+ (void)sayHappay;
@end

@interface LGStudent : LGPerson
- (void)sayHello;
+ (void)sayObjc;
@end

@interface NSObject (LG)
- (void)sayMaster;
+ (void)sayEasy;
@end

具体怎么实现的

/***********************************************************************
* _class_lookupMethodAndLoadCache.
* Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().
* This lookup avoids optimistic cache scan because the dispatcher 
* already tried that.
**********************************************************************/
IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
{
    return lookUpImpOrForward(cls, sel, obj, 
                              YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
}
/***********************************************************************
* lookUpImpOrForward.
* The standard IMP lookup. 
* initialize==NO tries to avoid +initialize (but sometimes fails)
* cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
* Most callers should use initialize==YES and cache==YES.
* inst is an instance of cls or a subclass thereof, or nil if none is known. 
*   If cls is an un-initialized metaclass then a non-nil inst is faster.
* May return _objc_msgForward_impcache. IMPs destined for external use 
*   must be converted to _objc_msgForward or _objc_msgForward_stret.
*   If you don't want forwarding at all, use lookUpImpOrNil() instead.
**********************************************************************/
IMP lookUpImpOrForward(Class cls, SEL sel, id inst, 
                       bool initialize, bool cache, bool resolver)
{
    IMP imp = nil;
    bool triedResolver = NO;

    runtimeLock.assertUnlocked();

    // Optimistic cache lookup
    if (cache) {
        imp = cache_getImp(cls, sel);
        if (imp) return imp;
    }

    // runtimeLock is held during isRealized and isInitialized checking
    // to prevent races against concurrent realization.

    // runtimeLock is held during method search to make
    // method-lookup + cache-fill atomic with respect to method addition.
    // Otherwise, a category could be added but ignored indefinitely because
    // the cache was re-filled with the old value after the cache flush on
    // behalf of the category.

    runtimeLock.lock();
    checkIsKnownClass(cls);

    if (!cls->isRealized()) {
        realizeClass(cls);
    }

    if (initialize  &&  !cls->isInitialized()) {
        runtimeLock.unlock();
        _class_initialize (_class_getNonMetaClass(cls, inst));
        runtimeLock.lock();
        // If sel == initialize, _class_initialize will send +initialize and 
        // then the messenger will send +initialize again after this 
        // procedure finishes. Of course, if this is not being called 
        // from the messenger then it won't happen. 2778172
    }

    
 retry:    
    runtimeLock.assertLocked();

    // Try this class's cache.
//防止动态添加方法,缓存会变化,再次查找缓存
    imp = cache_getImp(cls, sel);
//    查找到缓存之后,直接done ,返回方法地址
    if (imp) goto done;
//查找方法列表
    // Try this class's method lists.
    {//根据传入的类,方法 去查询是否存在
        Method meth = getMethodNoSuper_nolock(cls, sel);
        if (meth) {
            //存在方法 ,缓存方法 拿到imp 返回
            log_and_fill_cache(cls, meth->imp, sel, inst, cls);
            imp = meth->imp;
            goto done;
        }
    }

    // Try superclass caches and method lists.
//    去父类的缓存方法列表里查找
    {
        unsigned attempts = unreasonableClassCount();
        for (Class curClass = cls->superclass;
             curClass != nil;
             curClass = curClass->superclass)
        {
            // Halt if there is a cycle in the superclass chain.
            if (--attempts == 0) {
                _objc_fatal("Memory corruption in class list.");
            }
            
            // Superclass cache.查找父类的缓存
            imp = cache_getImp(curClass, sel);
            if (imp) {
                if (imp != (IMP)_objc_msgForward_impcache) {
                    // Found the method in a superclass. Cache it in this class.
// 在父类中找到方法, 在本类中缓存方法, 注意这里传入的是cls, 将方法缓存在本类缓存列表中, 而非父类中
                    log_and_fill_cache(cls, imp, sel, inst, curClass);
                    goto done;
                }
                else {
                    // Found a forward:: entry in a superclass.
                    // Stop searching, but don't cache yet; call method 
                    // resolver for this class first.
                    break;
                }
            }
            
            // Superclass method list.查找父类的方法列表
            Method meth = getMethodNoSuper_nolock(curClass, sel);
            if (meth) {
                //拿到方法,缓存本类
                log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
               //拿到imp goto done 返回
                imp = meth->imp;
                goto done;
            }
        }
    }

    // No implementation found. Try method resolver once.
    // 上述列表没有找到方法实现 - 进入动态解析阶段
    if (resolver  &&  !triedResolver) {
        runtimeLock.unlock();
        _class_resolveMethod(cls, sel, inst);
        runtimeLock.lock();
        // 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;
    }

    // No implementation found, and method resolver didn't help. 
    // Use forwarding.
// 没有方法实现 动态解析也没有 --进入 消息转发 阶段
    imp = (IMP)_objc_msgForward_impcache;
    cache_fill(cls, sel, imp, inst);

 done:
    runtimeLock.unlock();

    return imp;
}

//方法列表
static method_t *
getMethodNoSuper_nolock(Class cls, SEL sel)
{
    runtimeLock.assertLocked();

    assert(cls->isRealized());
    // fixme nil cls? 
    // fixme nil sel?
    // cls->data() 得到的是 class_rw_t
    // class_rw_t->methods 得到的是methods二维数组
    for (auto mlists = cls->data()->methods.beginLists(), 
              end = cls->data()->methods.endLists(); 
         mlists != end;
         ++mlists)
    {
        //mlists ->method_list_t
        method_t *m = search_method_list(*mlists, sel);
        if (m) return m;
    }

    return nil;
}

上一篇下一篇

猜你喜欢

热点阅读