断点调试找方法
- 断点调试创建People 类对象调用方法
- 按住control键一步步调试 最后会发现如下图所示 这里会调用objc_msgSend
继续按下control 往下走 回来到 接下来就看看_class_lookupMethodAndLoadCache3的方法实现
_class_lookupMethodAndLoadCache3
IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
{
return lookUpImpOrForward(cls, sel, obj,
YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
}
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.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);
if (imp) goto done;
// Try this class's method lists.
{
Method meth = getMethodNoSuper_nolock(cls, sel);
if (meth) {
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.
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 = 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;
}
分析
- IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver) 参数解读 cls 当前类 sel 当前方法的名字 inst 当前类对象 initialize 是否初始化 cache 是否缓存 resolver 是否在执行动态方法解析
- 如果缓存命中 直接返回imp
if (cache) {
imp = cache_getImp(cls, sel);
if (imp) return imp;
}
- 下边来看 realizeClass 我摘取主要的几行代码
static Class realizeClass(Class cls)
{
runtimeLock.assertLocked();
const class_ro_t *ro; // 方法列表 属性列表 等的存储结构题
class_rw_t *rw; // 存储 class_ro_t的结构题
Class supercls; // 父类
Class metacls; // 元类
bool isMeta; // 当前类是否是元类
ro = (const class_ro_t *)cls->data(); // 给ro赋值
isMeta = ro->flags & RO_META; // 是否是元类判断
supercls = realizeClass(remapClass(cls->superclass)); // 初始化父类
metacls = realizeClass(remapClass(cls->ISA())); // 初始化元类
cls->superclass = supercls; 找到当前类的 父类
cls->initClassIsa(metacls); 初始化当前类的元类
if (supercls) { // 如果有父类就把当前类关联到父类的子类列表中
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
- 如果类没有初始化就执行初始化 _class_initialize 的代码就不放了 主要作用就是 没有初始化的类进行初始化 如果有父类并且父类也没有初始化就连 父类也初始化掉 如果初始化完了就什么也不做 如果正在初始化 就等待
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
}
- 开始找方法 存储缓存
{
Method meth = getMethodNoSuper_nolock(cls, sel); // 一个for循环 从方法列表中找方法
if (meth) { // 如果找到方法 开始缓存
log_and_fill_cache(cls, meth->imp, sel, inst, cls); // 这里会调用 cache_fill 上一篇已经写过
imp = meth->imp;
goto done; // 找到直接返回
}
}
- 如果当前类没找到 就查找父类以及父类的父类 并且执行缓存 如果找到直接返回
for (Class curClass = cls->superclass;
curClass != nil;
curClass = curClass->superclass)
- 如果以上的过程都没有找到方法 那么就执行动态方法决议 也就是 if (resolver && !triedResolver) {这个判断体中的内容
- _class_resolveMethod 方法实现
void _class_resolveMethod(Class cls, SEL sel, id inst)
{
// 如果不是元类 说明是类 此时类中已经没有方法 直接执行 _class_resolveInstanceMethod
if (! cls->isMetaClass()) {
// try [cls resolveInstanceMethod:sel]
_class_resolveInstanceMethod(cls, sel, inst); // 执行 + (BOOL)resolveInstanceMethod:(SEL)sel方法
}
else {
// try [nonMetaClass resolveClassMethod:sel]
// and [cls resolveInstanceMethod:sel]
_class_resolveClassMethod(cls, sel, inst);
if (!lookUpImpOrNil(cls, sel, inst,
NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
{
_class_resolveInstanceMethod(cls, sel, inst); //
}
}
}
分析:
(1) 不是元类就找当前类的元类中是否有resolveInstanceMethod 如果没有直接返回 如果有就发送 resolveInstanceMethod 看看有没有动态添加方法 接着再执行方法查找流程
(2)是元类的时候: cls 就是元类 inst 类对象 这时会做两次尝试 第一次检查元类中是否有resolveClassMethod如果没有直接返回,如果有就直接发送resolveClassMethod消息再执行方法查找。如果resolveClassMethod方法没有动态添加方法就再执行一次 _class_resolveInstanceMethod 做一次容错,此时就会找到元类的元类就是根元类,再执行方法查找流程。最后会执行到NSObject的resolveInstanceMethod中。
- _class_resolveInstanceMethod方法源代码
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*/);
}
- 动态方法解析
实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"------resolveInstanceMethod---");
if (sel == @selector(happyNewYear)){
IMP imp = class_getMethodImplementation([self class], @selector(sayHello));
return class_addMethod(self, sel, imp, "v@:");
}
return [super resolveInstanceMethod:sel];
}
类方法
+ (BOOL)resolveClassMethod:(SEL)sel{
// 因为类方法在元类中查找 所以这里要向元类中添加类方法
if (sel == @selector(happySpring)){
IMP imp = class_getMethodImplementation(objc_getMetaClass("People"), @selector(sayGoodBy));
class_addMethod(objc_getMetaClass("People"), sel, imp, "v@:");
}
return [super resolveClassMethod:sel];
}
- 消息转发-重定向接收者
实例方法
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(happyNewYear)){
return [[Man alloc]init];
}
return [super forwardingTargetForSelector:aSelector];
}
类方法
+ (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(happySpring)){
return [Man class];
}
return [super forwardingTargetForSelector:aSelector];
}
- 消息转发-方法签名
实例方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(happyNewYear)){
return [[Man new] methodSignatureForSelector:aSelector];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
[anInvocation invokeWithTarget:[Man new]];
}
类方法
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(happySpring)){
return [Man methodSignatureForSelector:aSelector];
}
return [super methodSignatureForSelector:aSelector];
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation{
[anInvocation invokeWithTarget:[Man class]];
}
总结
iOS中方法的查找分为两部分 第一部分就是快速查找 在缓存中直接找到 发送消息,如果没找到就到了慢速查找 先找当前类 再找父类 已经父类的父类 如果找到就执行 如果找不到就执行动态方法解析和消息转发。