Objective-C的本质
我们平时编写的Objective-C代码,底层实现其实都是C\C++代码,Objective-C的对象、类主要是基于C\C++的结构体实现的
将Objective-C代码转换为C\C++代码:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
如果需要链接其他框架,使用-framework参数。比如-framework UIKit
一个OC对象在内存中是如何布局的?
OC对象的分类主要分为三个大类
实例对象,instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象object1、object2是NSObject的instance对象(实例对象)
// instance对象,实例对象
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
它们是不同的两个对象,分别占据着两块不同的内存
instance对象在内存中存储的信息包括
- isa指针
- 其他成员变量
类对象objectClass1 ~ objectClass5都是NSObject的class对象(类对象)
// class对象,类对象
// class方法返回的一直是class对象,类对象
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];
它们是同一个对象。每个类在内存中有且只有一个class对象
class对象在内存中存储的信息主要包括
isa指针
superclass指针
类的属性信息(@property)、类的对象方法信息(instance method)
类的协议信息(protocol)、类的成员变量信息(ivar)
......-
类方法信息
元类对象
每个类在内存中有且只有一个元类对象,元类对象和类对象的内存结构一样,但用途不一样。
元类对象在内存中存储的信息
- isa指针
- superClass的isa指针
// meta-class对象,元类对象
// 将类对象当做参数传入,获得元类对象
Class objectMetaClass = object_getClass(objectClass5);
类的获取
Class objc_getClass(const char *aClassName)
传入字符串类名
返回对应的类对象
Class object_getClass(id obj)
传入的obj可能是instance对象、class对象、meta-class对象
返回值
如果是instance对象,返回class对象
如果是class对象,返回meta-class对象
如果是meta-class对象,返回NSObject(基类)的meta-class对象
(Class)class、+ (Class)class
返回的就是类对象
指针
isa
instance的isa指向class
当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用
class的isa指向meta-class
当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用
supclass
supclass指针指向父类的类对象
class对象的superclass指针
当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用
meta-class对象的superclass指针
当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用
占用内存
创建一个实例对象,至少需要多少内存?
#import
class_getInstanceSize([NSObject class]);
创建一个实例对象,实际上分配了多少内存?
#import
malloc_size((__bridge const void *)obj);
isa指针占用8个字节,_no占用4个字节,_age占用4个字节
总结
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指向地址获取流程如下图
-
对象调用方法的轨迹
通过isa指针指向类对象,在类对象的实例方法列表中找,如果没找到,通过superclass指针向父类里面找,若果都没有找到,则会报错:No known class method for selector
-
类对象调用方法的轨迹
和对象调用方的轨迹类似,只不过是对象通过isa找到类对象,类对象通过isa找到元类对象,依次向上找,找到基类元类对象里面,如果基类元类对象里面也没有的话,会去基类的类对象里面找
举例说明: 对象中没有类方法 +test(),但是父类中有实例方法 -test(),这个时候调用 [Person test],会依次向上查找,直到再父类类对象中找到实例方法,可以调用 消息传递方式 objc_msgSend([Person class], @selector(test)) objc_msgSend(person, @selector(test)) isa -> superclass -> suerpclass -> superclass -> .... superclass == nil
objc_object结构
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
当前使用的都是OBJC2,所以这段结构基本上废弃了,现在为以下结构:
struct objc_class {
Class isa;
Class superclass;
cache_t cache; //方法缓存,是个table
class_data_bits_t bits; // 用于获取具体的类信息,是个table
}
& FAST_DATA_MASK 之后获得
struct class_rw_t {
uint32_t
Class isa;
Class superclass;
cache_t cache; //方法缓存,是个table
class_data_bits_t bits; // 用于获取具体的类信息,是个table
}
总结
对象的指针指向哪里
对象的isa指针指向类对象
类对象的isa指针指向元类的类对象
元类类对象的isa指针指向基类的元类类对象OC的类信息存放在哪里
实例对象方法、属性、成员变量(大小,类型,名字)、协议信息存放在类对象中
类方法存放在元类对象中
成员变量的具体值存放在实例对象
objc4源码下载