前段时间看到了这样的一个题目,觉得很有意思,所以决定写篇文章来分享一下
@interface NSObject (Sark)
+ (void)speak;
@end
@implementation NSObject (Sark)
- (void)speak {
NSLog("imp: [NSObject(Sark) speak]");
}
[NSObject speak]; 执行这行代码会发生什么?
@end
-
首先我们知道因为categroy 定义了+ (void)speak;所以这段代码再编译器是可以编译通过的。那么当我们具体执行到这行代码的时候,内部具体的消息查找流程到底是怎样的呢?我先po出一张图来让大家了解一下消息的查找机制
因为这是类方法,所以我们会根据isa指针先去NSObject的metaClass 去查找speak 的 sel,由于分类中只实现了- (void)speak。而metaClass的methodlist中存储的是类方法的sel,所以在metaClass中并不能去查找到speak的sel。这个时候会去NSObject metaClass的父类 Nsobject class的methodlist 去查找speak 的 sel。由于实现了- (void)speak方法,所以这个时候是可以在 Nsobject class的methodlist发现speak 的sel。然后根据sel找到了该imp。最后打印出了“imp: [NSObject(Sark) speak]”
看到这里可能会又有会有疑问,就是我明明调用的是类方法为什么最后却执行的是对象方法。那是因为OC的消息查找是根据sel的。而sel是不会区分类方法和示例方法的。所以这就是调用类方法最后去执行实例方法的原因了.
举一反三,看看下面的结果是什么?欢迎评论区回答
@interface Person: NSobject
+ (void)talk;
@end
@implementation Person
- (void)talk {
NSLog("imp: person talk");
}
@end
[Person talk];