入口
- 当
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();
if (! cls->isMetaClass()) {
resolveInstanceMethod(inst, sel, cls);
}
else {
resolveClassMethod(inst, sel, cls);
if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
resolveInstanceMethod(inst, sel, cls);
}
}
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:);
if (!lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA(/*authenticated*/true))) {
return;
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
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 {
_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所有未实现发方法,对其进行处理分析,也可以防止这种崩溃,通过这个方法上传崩溃的信息给后台