消息查找流程浅析学习
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;
}