接上篇OC底层原理(一)
平时自己都有学习一些底层原理,但是太过分散,也没有写过笔记,这次正好通过mj课程查漏补缺,也记录下来。
这篇还有一道面试题,我们还是在最后解答
问:对象的isa指针指向哪里?
之前我们一直说对象,但是其实我们说的都是实例对象,也就是instance对象,在Objective-C中的对象,其实有三种:
- instance对象(实例对象)
- class对象(类对象)
- meta-class对象(元类对象)
- instance对象
instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象
NSObjcet *object1 = [[NSObjcet alloc] init];
NSObjcet *object2 = [[NSObjcet alloc] init];
这是两个不同的实例对象,分别占据两块不同的内存。
实例对象在内存中存储的信息包括
- isa指针
- 其他成员变量
- class对象
我们通过class方法或runtime方法得到一个class对象。class对象也就是类对象
NSObjcet *object1 = [[NSObjcet alloc] init];
NSObjcet *object2 = [[NSObjcet alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = [NSObject class];
// runtime
Class objectClass4 = object_getClass(object1);
Class objectClass5 = object_getClass(object2);
objectClass1~~ objectClass5都是类对象,他们是同一个类对象,每一个类在内存中有且只有一个class对象。
class对象在内存中存储的信息主要包括
- isa指针
- superclass指针
- 类的属性信息(@property),类的成员变量信息(ivar)类的对象方法信息(instance method),类的协议信息(protocol)
- meta-class对象
runtime方法object_getClass中传入类对象,得到的就是元类对象
//runtime方法object_getClass中传入类对象,得到的就是元类对象
Class objectMetaClass = object_getClass([NSObject class]);
// 但是调用类对象的class方法时得到还是类对象,无论调用多少次都是类对象
Class objectClass3 = [NSObject class];
Class cls = [[NSObject class] class];
PS:为什么上面调用class方法还是返回类对象,可以查看到其源码。
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
//object_getClass方法实现,在其他文件中,一起贴过来了
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
上面第一段代码中objectMetaClass是NSObject的meta-class对象(元类对象)
每个类在内存中有且只有一个meta-class对象。
meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括
- isa指针
- superclass指针
- 类的类方法的信息(class method)
meta-class对象和class对象的内存结构是一样的,只是因为存储信息不一样,有的信息是空的,图中只是展示了主要信息。
isa指针
这里就要放这张图了
image.png
isa、superclass总结
- instance的isa指向class
- class的isa指向meta-class
- meta-class的isa指向基类的meta-class,基类的isa指向自己
- class的superclass指向父类的class,如果没有父类,superclass指针为nil
- meta-class的superclass指向父类的meta-class,基类的meta-class的superclass指向基类的class
- instance调用对象方法的轨迹,isa找到class,方法不存在,就通过superclass找父类
- class调用类方法的轨迹,isa找meta-class,方法不存在,就通过superclass找父类
为了证明isa指针的指向是不是我们上面所说的那样,我们用代码来试一下。
image.png通过断点log出来person对象的isa指针和personClass对象的地址来看,他们并不一样。为什么呢?实际上从苹果64位系统开始,isa还需要一次位运算才能得到真正所指向的真实地址,位运算可以在objc4源码中找到。
//这里是简化后的内容,只取了我们需要的
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
因为我们是在mac上进行所以应该是x86架构,我们进行一下运算
image.png
这里我们就能看到person实例对象的isa指针指向的地址0x001d800100001229进行位运算&0x00007ffffffffff8之后,得到的最终地址就是0x0000000100001228,和personClass这个类对象地址一致,也验证了我们的说法。
然后我们再看一下personClass(类对象)的isa是不是指向personMetaClass(元类对象)
对于类对象,我们已经知道了它的结构并且结构里肯定是有isa指针这个成员,这里我们自己定义一个结构体强制转换一下,拿到这个isa指针
image.png
然后我们再看一下isa指针的地址
image.png
我们发现经过转换后取到personClass(类对象)的isa同样需要经过位运算得到personMetaClass(元类对上)的地址。
验证完成
面试题解答
问:对象的isa指针指向哪里?
答:instance对象的isa指针指向class对象,
class对象的isa指针指向meta-class对象,
meta-class对象的isa指针指向基类的meta-class对象,
基类的meta-class的isa指针也指向自己。
网友评论