方法查找不到报错原因
慢速查找过程中,如果最终查找不到,会返回一个forward_imp
const IMP forward_imp = (IMP)_objc_msgForward_impcache;
复制代码
全局搜索_objc_msgForward_impcache
STATIC_ENTRY __objc_msgForward_impcache
// No stret specialization.
b __objc_msgForward
END_ENTRY __objc_msgForward_impcache
ENTRY __objc_msgForward
adrp x17, __objc_forward_handler@PAGE
ldr p17, [x17, __objc_forward_handler@PAGEOFF]
TailCallFunctionPointer x17
END_ENTRY __objc_msgForward
复制代码
可以发现最终走到了__objc_forward_handler,全局搜索__objc_forward_handler,搜索不到,去掉__再次搜索,
__attribute__((noreturn, cold)) void
objc_defaultForwardHandler(id self, SEL sel)
{
_objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
"(no message forward handler is installed)",
class_isMetaClass(object_getClass(self)) ? '+' : '-',
object_getClassName(self), sel_getName(sel), self);
}
void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
复制代码
可以发现错误打印函数objc_defaultForwardHandler。
动态方法决议
慢速查找流程中,如果查找不到,会进入下面流程behavior为3,LOOKUP_RESOLVER为2,behavior & LOOKUP_RESOLVER 和behavior ^= LOOKUP_RESOLVER结合,实现单例模式,只能进入一次。
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior);
}
复制代码
查看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()) {
// 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);
}
}
return lookUpImpOrForwardTryCache(inst, sel, cls, behavior);
}
复制代码
resolveInstanceMethod
如果! cls->isMetaClass()不是元类,即对象方法,进入resolveInstanceMethod函数
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))) {
// Resolver not implemented.
return;
}
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函数发送消息
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(cls, resolve_sel, sel);
复制代码
然后再次进入缓存查找imp,如果我们在resolveInstanceMethod函数给sel返回一个imp,是否程序就可以补救
IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
复制代码
resolveInstanceMethod实现
添加一个类LKPerson,添加方法sayHello,但不实现。实现方法
- (void)teacherSayHello{
NSLog(@"%@ - %s",self , __func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"resolveInstanceMethod :%@-%@",self,NSStringFromSelector(sel));
if (sel == @selector(sayHello)) {
IMP sayHelloImp = class_getMethodImplementation(self, @selector(teacherSayHello));
Method method = class_getInstanceMethod(self, @selector(teacherSayHello));
const char *type = method_getTypeEncoding(method);
return class_addMethod(self, sel, sayHelloImp, type);
}
return [super resolveInstanceMethod:sel];
}
复制代码
可以看到程序并没有崩溃,并且打印teacherSayHello。
resolveClassMethod
如果! cls->isMetaClass()是元类,即实例方法,进入resolveClassMethod函数
static void resolveClassMethod(id inst, SEL sel, Class cls)
{
runtimeLock.assertUnlocked();
ASSERT(cls->isRealized());
ASSERT(cls->isMetaClass());
if (!lookUpImpOrNilTryCache(inst, @selector(resolveClassMethod:), cls)){
// Resolver not implemented.
return;
}
Class nonmeta;
{
mutex_locker_t lock(runtimeLock);
nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
// +initialize path should have realized nonmeta already
if (!nonmeta->isRealized()) {
_objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
nonmeta->nameForLogging(), nonmeta);
}
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
// Cache the result (good or bad) so the resolver doesn't fire next time.
// +resolveClassMethod adds to self->ISA() 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 resolveClassMethod:%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));
}
}
}
复制代码
resolveClassMethod与resolveInstanceMethod函数类似
Class nonmeta;
{
mutex_locker_t lock(runtimeLock);
nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
// +initialize path should have realized nonmeta already
if (!nonmeta->isRealized()) {
_objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
nonmeta->nameForLogging(), nonmeta);
}
}
BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
bool resolved = msg(nonmeta, @selector(resolveClassMethod:), sel);
复制代码
nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);根据元类,获取当前类
向类发送resolveClassMethod消息,然后再次查找imp。
resolveClassMethod实现
添加实例方法,但不实现。
+ (void)classSayHello;
+ (void)classTeacherSayHello{
NSLog(@"%@ - %s",self , __func__);
}
+ (BOOL)resolveClassMethod:(SEL)sel{
NSLog(@"resolveClassMethod :%@-%@",self,NSStringFromSelector(sel));
if (sel == @selector(classSayHello)) {
IMP sayHelloImp = class_getMethodImplementation(objc_getMetaClass("LKPerson"), @selector(classTeacherSayHello));
Method method = class_getInstanceMethod(objc_getMetaClass("LKPerson"), @selector(classTeacherSayHello));
const char *type = method_getTypeEncoding(method);
return class_addMethod(objc_getMetaClass("LKPerson"), sel, sayHelloImp, type);
}
return [super resolveClassMethod:sel];
}
复制代码
打印classTeacherSayHello。
























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)