OC对象的本质

Objective-C

Objective-C是C语言的超集,我们平时写得OC,底层的实现都是C\C++代码,OC的对象、类是基于C\C++的结构体实现的。
可以使用以下命令行将OC代码转换为C\C++代码(只能作为参考不一定百分百准确)

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc  -o <输出的.cpp文件>

如果需要链接其他框架,使用- framework参数,比如-framework UIKit

NSObject

一般我们写的对象都继承于NSObject,所以弄清楚NSObject相当关键

  • NSObject底层实现相关源码
struct NSObject_IMPL{
  Class *isa
}
//Class是objc_class结构体指针
typedef objc_class *Class

NSObject类里只有Class isa指针,所以obj对象的地址值就是isa指针的地址值。表面上看之只占用了8个字节(指针变量8个字节),阅读OC源码可以看到实质是分配了16个字节。
可以使用以下API查看内存使用情况

//一个实例对象至少需要多少字节
class_getInstanceSize([NSObject class]);
//一个实例对象实际占用多少字节
malloc_size((__brige const void *)obj);

一个继承NSObject的类的结构体

//例如
@interface Person : NSObject
@property (nonatomic, assign) int age;
@end
struct Person_IMPL{
  stuct NSObject_IMPL NSObject_IVARS;
  int _age;
}
//NSObject_IMPL的成员变量只有isa指针一个,所以实际结构体等价如下,person实例对象的地址值还是isa指针的地址值,再继承也同理
struct Person_IMPL{
  Class *isa;
  int _age;
}
OC对象分类

OC对象分为三类:instance对象(实例对象)、class对象(类对象)、meta-class对象(元类对象)

  • instance对象:通过类alloc出来的对象,每次alloc都会创建新的实例对象
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
//obj1、obj2都是instance对象,它们是不同的两个对象,分别占据着不同的内存

instance对象在内存中存储的信息有isa指针和其他成员变量。

  • class对象(类对象)
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];

objectClass1 ~ objectClass5都是NSObject的class对象
它们都是同一个对象,每一个类在内存中有且只有一个class对象
class对象在内存中存储的信息主要包括:
isa指针
superclass指针
类的属性信息(@property)、类的对象方法信息(instance method)
类的协议信息(protocol)、类的成员变量信息(ivar)

  • meta-class(元类对象)
//获取元类对象的方法
Class objMetaClass = object_getClass([NSObject class]);
/*
  注意:这个方法获取到的还是类对象
  Class objMetaClass = [[NSObject class] class];
*/

objectMetaClass是NSObject的meta-class对象(元类对象)
每个类在内存中有且只有一个meta-class对象
meta-class对象和class对象的内存结构是一样的,只是用途不一样而已,在内存中存储的信息主要包括:
isa指针
superClass指针
类的类方法信息
......

  • Class的结构
//struct objc_class 结构
struct objc_class{
  Class isa;
  Class superclass;
  Cache_t cache;//方法缓存
  class_data_bit_t bit;//用于获取类的具体信息
}
// bit & FAST_DATA_MASK 得到类的具体信息
struct class_rw_t {  // rw表示可读写
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;
    method_array_t methods; //method_t 二维数组
    property_array_t properties; //属性二维数组
    protocol_array_t protocols; //协议二维数组
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
}
//struct class_ro_t 的结构
struct class_ro_t { //ro表示只读
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif
    const uint8_t * ivarLayout;
    const char * name; //类名
    method_list_t * baseMethodList; //方法列表
    protocol_list_t * baseProtocols; //协议列表
    const ivar_list_t * ivars; //成员变量列表
    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
}
isa指针和supclass指针
  • instance的isa指针指向class
    instance调用对象方法时,通过isa指针找到class,找出对应的对象方法进行调用
  • class的isa指针指向meta-class
    调用类方法时,通过class的isa找到meta-class,找出对应的类方法进行调用

从Arm64开始,优化了isa指针,isa & ISA_MASK才是真正的地址值

  • class对象的superclass指针指向父类class对象
    当instance调用父类对象方法时,先通过isa指针找到class,再通过class对象的superclass指针找到父类,然后再找出对应对象方法进行调用
  • meta-class对象的superclass指针指向父类的meta-class对象
    调用父类类方法时,通过class的isa找到meta-class,再通过meta-class对象的superclass指针找到父类,然后再找出对应的类方法进行调用


    isa、superclass总结

你可能感兴趣的:(OC对象的本质)