入口
- 当
lookUpImpOrForward
通过sel
查找imp
找不到时
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior);
}
enum {
LOOKUP_INITIALIZE = 1,
LOOKUP_RESOLVER = 2,
LOOKUP_NIL = 4,
LOOKUP_NOCACHE = 8,
};
复制代码
- 根据汇编我们看到
behavior = LOOKUP_INITIALIZE | LOOKUP_RESOLVER
, 所以behavior = 1 | 2 = 3
behavior & LOOKUP_RESOLVER
=3 & 2
=2
behavior ^= LOOKUP_RESOLVER;
=2 ^ 2
=0
behavior = 0
, 当其在与上其他时,一直都是0,其实就相当于一个标记,所以这里方法只会走进来一次
resolveMethod_locked分析
static NEVER_INLINE IMP
resolveMethod_locked(id inst, SEL sel, Class cls, int behavior)
{
runtimeLock.assertLocked();
ASSERT(cls->isRealized());
runtimeLock.unlock();
// cls 不是元类
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
// 再查找一次
return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);
}
复制代码
对象方法动态解析
static void resolveInstanceMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
SEL resolve_sel = @selector(resolveInstanceMethod:);
// 查看缓存里有没有 resolve_sel, 就是有没有实现 resolveInstanceMethod 方法
// 系统默认有实现 所以不会走 return
if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
// Resolver not implemented.
return;
}
// 消息发送调用 resolveInstanceMethod 方法
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
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
// 在查看一下调用的方法有没有
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
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));
}
}
}
复制代码
- 如果查找方法没有找到,根据上面代码的逻辑可以看出,我们只要对象方法实现了
resolveInstanceMethod
- 没有实现
look
方法,但是我们通过resolveInstanceMethod
,将look
的sel
绑定到了hear
的imp
上 - 最终调用的是
hear
方法
类方法动态解析
- 我们知道类方法,存在元类里,类方法就是元类的实例方法
- 所以可以将
eat
方法 动态解析到say
方法
NSObject+Catagory
对象方法 -> 类 -> 父类 > NSObject
类方法 -> 元类 -> 父类 -> 根元类 -> NSObject
- 最终都会走到
NSOject
, 所以我们只需要在NSObject 的类别里实现resolveInstanceMethod
就可以拦截到所有未实现的sel
- 一样不会
crash
, 会调用对应的方法 - 这样就可以
hook
所有未实现发方法,对其进行处理分析,也可以防止这种崩溃,通过这个方法上传崩溃的信息给后台
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END