OC对象的分类
OC中的对象,简单来说可以分为三大类:instance 对象(实例对象)、class 对象(类对象)、meta-class 对象(元类对象)。
isa
三种对象在内存中分别存储着不同的内容,具体如下图所示:
Teacher 对象的 isa 指向 class 对象。当调用对象方法时,通过实例对象的 isa 找到类对象,最后找到类对象中存储的对象方法进行调用。
class 对象的 isa 指向 meta-class 对象。当调用类方法时,通过类对象的 isa 找到元类对象,最后找到元类对象中存储的类方法进行调用。
superclass
假若当前存在 Person 类和 Teacher 类,其中 Person 类继承自 NSObject 类,Teacher 类继承自 Person 类,则各个 class 对象的 superclass 指针指向如下图所示:
当 Teacher 的 instance 对象要调用 Person 的对象方法时,会先通过 isa 找到 Teacher 的 class,然后通过 superclass 找到 Person 的 class,最后找到对象方法的实现进行调用。 同理,各个 meta-class 对象的 superclass 指针指向如下图所示:
当 Teacher 的 class 对象要调用 Person 的类方法时,会先通过 isa 找到 Teacher 的 meta-class,然后通过 superclass 找到 Person 的 meta-class,最后找到类方法的实现进行调用。
isa、superclass总结
借用一下网上很火的总结图(个人觉得很到位~)
instance 的 isa 指向 class。
class 的 isa 指向 meta-class。
meta-class 的 isa 指向基类的 meta-class。
class 的 superclass 指向父类的 class。如果没有父类,superclass 指向为 nil。
meta-class 的 superclass 指向父类的 meta-class。基类的 meta-class 的 superclass 指向基类的 class。
instance 调用对象方法的轨迹:isa 找到 class,方法不存在,就通过 superclass 找父类。
class 调用类方法的轨迹:isa 找到 meta-class,方法不存在,就通过 superclass 找父类。
相关问题
为了考验大家对 isa 和 superclass 的理解程度,接下来我们探索个有趣的问题:
首先创建一个 NSObject 的分类 NSObject (Utils) ,在其.m文件中实现对象方法 -classMethodTest
。
再创建一个 QLPerson 类,在.h文件中声明类方法+ (void)classMethodTest
,但.m文件中并无该方法实现。
问:调用[QLPerson classMethodTest];
方法会发生什么现象?
// NSObject+Utils.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Utils)
@end
NS_ASSUME_NONNULL_END
// NSObject+Utils.m
#import "NSObject+Utils.h"
@implementation NSObject (Utils)
- (void)classMethodTest {
NSLog(@"%s", __func__);
}
@end
// main.m
#import <Foundation/Foundation.h>
#import "NSObject+Utils.h"
@interface QLPerson : NSObject
+ (void)classMethodTest;
@end
@implementation QLPerson
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[QLPerson classMethodTest];
}
return 0;
}
分析:
根据前面所总结的,我们知道在调用[QLPerson classMethodTest];
时,实际上是QLPerson 的 isa 先找到 QLPerson 的 meta-class,在 QLPerson 的 meta-class 中并没有找到+ classMethodTest
方法的实现,接下来会通过 QLPerson 中 meta-class 的 superclass 指针去找父类 NSObject 的 meta-class,在 NSObject 的 meta-class 中也没有找到+ classMethodTest
方法的实现,便会继续通过 NSObject 中 meta-class 的 superclass 指针去找其父类,因为 NSObject 是基类,故其元类的父类指向其类本身,即 NSObject 的 class。又因 NSObject 的 class 中存储的对象方法中包含了 -classMethodTest
,所以方法找到了,调用即可。
结果:
最终的结果是会调用分类 NSObject (Utils) 的 -classMethodTest
方法,打印结果如下:
好啦,先到此为止,后续若有新发现,会继续更新。 欢迎大家指正与分享~