iOS小知识之元类

123 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

在iOS中,将实例对象的isa进行&运算,可得到类对象的地址。同样类也是一个对象,也有自己的数据结构,如果将类对象的isa & ISA_MASK,会得到什么呢?我们就来探索一下。 打开main.m文件,写入以下代码:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LGPerson *p = [LGPerson alloc]; 
        NSLog(@"%@",p); 
    }
    return 0; 
}

打印出实例对象的数据结构,我们可以得到实例对象的isa

x/4g p 
------------------------- 
0x100547b50: 0x011d800100008365 0x0000000000000000 
0x100547b60: 0x0000000000000000 0x0000000000000000
  • isa:0x011d800100008365 通过isa & ISA_MASK可以得到类对象的地址
p/x 0x011d800100008365 & 0x00007ffffffffff8ULL 
------------------------- 
0x0000000100008360

将地址进行po打印,可以发现

po 0x0000000100008360 
------------------------- 
LGPerson
  • 实例对象p的isa,指向LGPerson类 接着打印LGPerson的数据结构
x/4g 0x0000000100008360 
------------------------- 
0x100008360: 0x0000000100008338 0x00007fff80670008 
0x100008370: 0x0000000100712880 0x0002802c00000003
  • isa:0x0000000100008338 将类对象isa进行&运算
p/x 0x0000000100008338 & 0x00007ffffffffff8ULL 
------------------------- 
0x0000000100008338
  • 得到相同的地址 将地址进行po打印
po 0x0000000100008338
------------------------- 
LGPerson

分别使用实例对象和类对象的isa & ISA_MASK,得到的地址完全不同,但打印结果同样是LGPerson

0x100008360 = LGPerson = 0x100008338

此时我们是不是可以这样大胆设想,同一个类在内存中不只有一个,它可能和对象一样,可以无限开辟 元类初探 写入以下代码,帮助我们来初探元类

Class class1 = [LGPerson class]; 
Class class2 = [LGPerson alloc].class; 
Class class3 = object_getClass([LGPerson alloc]);

NSLog(@"class1:%p", class1); 
NSLog(@"class2:%p", class2); 
NSLog(@"class3:%p", class3);

------------------------- 

//输出结果: 
class1:0x100008360 
class2:0x100008360 
class3:0x100008360
  • 很明显通过测试结果可以看出,真正的LGPerson类,地址为0x100008360 所以0x100008338又是什么呢?

在OC中,类也是一个对象。既然是对象,也会存在isa指针,指向它所属的类。就是我们所说的元类(MetaClass) 在代码中,我们无法找到元类的代码。它是由系统生成和编译的,可使用MachOView查看

image-4.png -0x100008338:就是LGPerson类所属的元类 所以,我们可以得出结论:

  • 实例对象的isa -> 类isa -> 元类