iOS Runtime之isa指针探索与object_setClass的实质

iOS Runtime之isa指针探索与object_setClass的实质

探索isa的指向

测试代码:

@interface Company : NSObject
@property (assign, nonatomic) int cid;
@end

    Company *company = [Company new];
    company.cid = 255;
    NSLog(@"address: %p", company);

打印对象地址:

通过View Memory查看地址为0x600000db4630的内存信息:

该内存区域可以分为两个部分,前面8个字节属于isa字段,值为0x010aad2b98(从高地址向低地址读);后一个字节属于company的cid字段,值为0xff=255。

按照上面的步骤继续查看isa指向的地址的内容,可以得出isa的指向关系:

iOS Runtime之isa指针探索与object_setClass的实质_第1张图片

最终NSObject的isa指向了自己:

instance.isa = class
class.isa = metaclass
metaclass.isa = metaclass.superclass.superclass…metaclass (metaclass.isa指向顶层的父类的metaclass)

iOS Runtime之isa指针探索与object_setClass的实质_第2张图片

使用object_setClass会发生什么

下面测试Company的类型转为User类型。

代码:

@interface User : NSObject
@property (assign, nonatomic) int uid;
@property (assign, nonatomic) int height;
@property (assign, nonatomic) int age;
@end
@interface Company : NSObject
@property (assign, nonatomic) int cid;
@end
    Company *company = [Company new];
    company.cid = 255;
    NSLog(@"address: %p", company);
    object_setClass(company, [User class]);
    NSLog(@"address: %p", company);

打印company地址:

内存布局,前8字节是isa,指向Company;后一个字节是cid,值为0xFF

执行object_setClass后,对象的地址没有改变:

iOS Runtime之isa指针探索与object_setClass的实质_第3张图片

查看内存布局:

iOS Runtime之isa指针探索与object_setClass的实质_第4张图片

可以看到isa的值发生了变化,变为了[User class],而原本的cid部分的值并没有清空,仍然是0xff

尝试打印User的实例变量的值:

iOS Runtime之isa指针探索与object_setClass的实质_第5张图片

由于原Company的实例变量cid所在地址被User.uid取代了,所以将uid打印出来的值是原来cid的值;height字段所在位置刚好全是0,所以打印出的值为0;age所在位置应该是未初始化的区域,所以值是随机的。

总结

  • 使用object_setClass后会使对象的isa的值指向新的Class。
  • 使用object_setClass对象的内存布局不会发生变化。
  • 使用object_setClass不能访问超过原对象申请的内存区域,否则程序会crash。

其他问题

iOS Runtime之isa指针探索与object_setClass的实质_第6张图片

在调试的时候发现,系统总是以16个字节为单位来分配内存:

原因:
最低消费16Bytes:

size_t instanceSize(size_t extraBytes) {
     size_t size = alignedInstanceSize() + extraBytes;
      // CF requires all objects be at least 16bytes.
      if (size < 16) size = 16;
      return size; 
}

具体原因是Apple系统中的malloc函数分配内存空间时,内存是根据一个bucket的大小来分配的. bucket的大小是16,32,48,64,80 …,可以看出系统是按16的倍数来分配对象的内存大小的。

参考资料

iOS底层原理(一):OC对象实际占用内存与开辟内存关系
https://www.jianshu.com/p/b4d049be01aa

你可能感兴趣的:(iOS)