类对象存储实例方法列表等信息
元类对象存储类方法列表等信息
先献祭出一副官方的图
这幅图相信大多数做iOS的都不会陌生。
这里,我们就来描述一下图中所表述的isa
以及superclass
的指向情况。
首先,我们在上面的内容中,已经知道了所有的类实际上都是一个对象,我们称之为类对象。当我们声明实例的时候,所声明的实例对象的isa指针就指向这些类对象,这些类对象存储了实例方法(也就是-方法),而这些类对象也拥有isa指针,他们的指向了MetaClass对象。这些MetaClass对象负责存储类类方法(+方法)。与类对象样,MetaClass也是objc_class结构,所以也拥有isa指针,这些isa指针都指向根元类对象(Root MetaClass),
而根元类对象的isa指针指向根元类对象本身。这样就构成了一个闭环。
再看看superclass指针,首先对于类对象,是一层层的继承关系。各自的superclass指向其父类,类对象的最顶层superclass指向nil,对于元类对象也是直线各自的父类。这里需要重点说明的是,根元类对象的superclass指向的是其类对象。也就是说,当根元类对象在查找类方法中没找到对应的方法,那么就会去实例方法列表中去查找。
我们来分析例子,如果我们调用最下层(最左下角)的实例的实例方法,方法的查找流程是怎样的?
- 先根据isa指针找到类对象,遍历类对象中的方法列表
- 没找到依次查找父类的方法列表
- 到nil
再如果我们调用最下层(最左下角)的实例的类方法,方法的查找流程是怎样的?
- 先根据isa找到类方法
- 再找到类方法的isa指针指向的MetaClass,遍历类方法列表
- 没找到依次查找父类的方法列表
- 直到根元类都未找到时,查找根类对象
- 到nil
到这里,应该可以理解实例对象的方法查找流程,与类方法的方法查找流程了吧!
再来看一个面试题
#import "Father.h"
@interface Son: Father
@end
@implementation Son
- (instancetype)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
上面的面试题的答案是打印2个Son。我们来分析一下。
class方法的的实现是在NSObject当中的,所以这两个方法的class方法最终都要调用到NSObject的class方法。而super
这个关键字,实际上返回的消息接受者依然是Son,所以两个的输出是相同的。只不过是从当前类对象(Son的类对象)的父类对象(Father的类对象)开始查找方法实现。