- 在上节博客(慢速查找分析)中提到了
动态方法决议。今天我们就了解一波动态方法决议!!
1. 定位关键方法
-
- 我们已经知道--在查找时(
lookUpImpOrForward)中,在没有找到imp的最后,给了一次补救的机会~
- 我们已经知道--在查找时(
// No implementation found. Try method resolver once.
if (slowpath(behavior & LOOKUP_RESOLVER)) {
behavior ^= LOOKUP_RESOLVER;
return resolveMethod_locked(inst, sel, cls, behavior);
}
直接看也不知道这是啥,所以大家要养成会看注释的习惯。。
-
注释的意思:没有发现实现。试图调用方法在解决一次
-
- 我们点进去先大致浏览下,然后重点分析(毕竟一开始就读懂每一行,感觉像个憨憨。。(原先我就是。。😆))
-
- 我们观察到:2个核心方法:
resolveInstanceMethod、resolveClassMethod!
- 我们观察到:2个核心方法:
根据字面意思也知道,一个是解决实例方法,一个是解决类方法。
2. 探索分析
动态方法决议包括:
对象的动态方法决议,类的动态方法决议
2.1. 对象方法的动态方法决议
resolveInstanceMethod
2.1.1. 验证猜想
-
- 我们分析方法的时候,首先要找到关键的代码,哪一行取决定作用,我画了一波图分析(从后向前定位)
- 我们分析方法的时候,首先要找到关键的代码,哪一行取决定作用,我画了一波图分析(从后向前定位)
-
- 既然找到了这个关键的东西,那我们搜索下,这在哪里调用了
- 既然找到了这个关键的东西,那我们搜索下,这在哪里调用了
-
- 这个返回NO,感觉就是什么都没有处理~ :那就断点调试呗,看他是不是会走~
-
- 那我就掉一个有声明,没有实现的方法!!(大家也都知道,要走到补救的时候,说明在之前没有找到)
XGTest *test = [XGTest alloc];
Class tClass = [test class];
[test say5];
-
- 真会走~~~~!!那我们看下堆栈
- 真会走~~~~!!那我们看下堆栈
这和我们分析的流程一样啊
2.1.2. 方法运用
这个时候我们会想到一种思路:如果我们重写一下这个方法,然后给
sel关联一个imp,理论上是不是就没有问题了?
有兄弟说:你也知道是理论上!!,那我肯定要实践一波啊~
如果一个类有分类的话,优先调用分类的方法(相同方法)。(这个就不在这篇博客说明了啊)
-
- 我们创建
NSObject分类,搞上一波(😆)
- 我们创建
-
- 先创建后,打条log,证明他曾经来过。
- 先创建后,打条log,证明他曾经来过。
-
- 看输出
- 看输出
他来过~~~
-
- 我们的思路:
sel是没有知道不到对应的imp,所以崩掉。。我们给他个~
- 我们的思路:
#import <objc/message.h>
- (void)instanceMethodFix{
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"%s--%@",__func__,NSStringFromSelector(sel));
if (sel == @selector(say5)){
IMP imp = class_getMethodImplementation(self, @selector(instanceMethodFix));
Method method = class_getInstanceMethod(self, @selector(instanceMethodFix));
const char * type = method_getTypeEncoding(method);
return class_addMethod(self, sel, imp, type);
}
return NO;
}
我们获取实例方法
instanceMethodFix的imp,然后把say5的sel关联上他,兄弟们。我运行下.
他没有崩溃!!他没有崩溃!!他没有崩溃!!
-
- 结论:我们的分析是正确的,查找不到 苹果给了他一次补救的机会
走到这个方法里面说明方法没有找到的 -- 至于怎么用,就要看你们了~
2.2. 类方法的动态方法决议
研究完对象的动态方法决议,类的就显得简单些了~
-
- 我们找到这个方法的核心
- 我们找到这个方法的核心
-
- 先搞一波调用类方法的代码
[XGTest say6];//方法没有实现
-
- 我们可以继续在分类中创建方法!然后看是不是一样的原理!
- (void)classMethodFix{
NSLog(@"%s",__func__);
}
+ (BOOL)resolveClassMethod:(SEL)sel{
NSLog(@"%s--%@",__func__,NSStringFromSelector(sel));
if (sel == @selector(say6)) {
IMP imp = class_getMethodImplementation(self, @selector(classMethodFix));
Method method = class_getClassMethod(self, @selector(classMethodFix));
const char *type = method_getTypeEncoding(method);
return class_addMethod(self, sel, imp, type);
}
return NO;
}
** 我们运动打印一波,卧槽!崩了!!! **
-
- 这个时候,要引进一波,isa的走位图了
- 这个时候,要引进一波,isa的走位图了
-
- 其实细心的兄弟们,应该也发现了个问题:就是在处理
resolveClassMethod的时候
- 其实细心的兄弟们,应该也发现了个问题:就是在处理
兄弟们,我创建的是
NSObject的分类~(哈哈😆,也不知道这调皮的性格跟谁学的~)。至于怎么改成正确的大家应该也知道了(有些东西不能说的太明,否则会打消兄弟们探索的积极性~)
-
- 那这样的话其实就可以在
resolveInstanceMethod中全部搞定了~
- 那这样的话其实就可以在
- (void)instanceMethodFix{
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"%s--%@",__func__,NSStringFromSelector(sel));
if (sel == @selector(say5)){
IMP imp = class_getMethodImplementation(self, @selector(instanceMethodFix));
Method method = class_getInstanceMethod(self, @selector(instanceMethodFix));
const char * type = method_getTypeEncoding(method);
return class_addMethod(self, sel, imp, type);
}else if (sel == @selector(say6)){
IMP imp = class_getMethodImplementation(self, @selector(instanceMethodFix));
Method method = class_getInstanceMethod(self, @selector(instanceMethodFix));
const char * type = method_getTypeEncoding(method);
return class_addMethod(self, sel, imp, type);
}
return NO;
}
哈哈,发现就OK了~
最好的记录方法就是兄弟们自己去探索一波~👌