OC 消息机制 Objective-C 语言 中,对象方法调用都是类似 [receiver selector]; 的形式,其本质就是让对象在运行时发送消息的过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Receiver *receiver = [[Receiver alloc] init]; [receiver message]; objc_msgSend(receiver, @selector (message)); if ([receiver respondsToSelector:@selector (message)]) { [receiver performSelector:@selector (message)]; }
编译阶段:[receiver selector]; 方法被编译器转换为: objc_msgSend(recevier,selector,org1,org2,…)
运行时阶段:消息接受者 recever 寻找对应的 selector。
通过 recevier 的 isa 指针 找到 recevier 的 Class(类);
在 Class(类) 的 cache(方法缓存) 的散列表中寻找对应的 IMP(方法实现);
如果在 cache(方法缓存) 中没有找到对应的 IMP(方法实现) 的话,就继续在 Class(类) 的 method list(方法列表) 中找对应的 selector,如果找到,填充到 cache(方法缓存) 中,并返回 selector;
如果在 Class(类) 中没有找到这个 selector,就继续在它的 superClass(父类)中寻找;一旦找到对应的 selector,直接执行 recever 对应 selector 方法实现的 IMP(方法实现)。
若找不到对应的 selector,消息被转发或者临时向 recever 添加这个 selector 对应的实现方法,否则就会发生崩溃。
OC 类与对象 OC Class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #import <objc/runtime.h> #import <objc/objc.h> 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; struct objc_class : objc_object { isa_t isa; Class superclass; cache_t cache; class_data_bits_t bits; }; typedef struct objc_class *Class;
isa:是一个不能为空(null)的Class对象,它指向自己的创建者(类或元类)。
super_class:是一个可以为空的Class对象,它指向当前类的父类。
ivars:是实例变量列表,保存着该类的所有实例变量。
methodLists:是方法列表,保存着实例方法和类方法。
protocols:是协议列表,保存该类的协议方法。
cache:是一个缓存,用于缓存最近使用过的方法。
OC Object 1 2 3 4 5 6 7 struct objc_object { Class isa OBJC_ISA_AVAILABILITY; }; typedef struct objc_object *id ;
一个 Object(对象)唯一保存的就是它所属 Class(类) 的地址。
OC 实例对象、类、元类关系
instance 实例对象是由类创建出来的对象,根据实际情况,内存中存在多份。实例对象通过isa指针指向类(对象)。
class 类是实例对象的描述,保存了实例对象的定义。同时,类也是元类的对象(类对象),内存中只有一份。类对象通过isa指针指向元类(对象)。
metaclass 元类是类对象的描述。元类对象的isa指针指向根元类,即由根元类创建的元类。根元类的isa指针指向自己,形成一个封闭的内循环。
实线的箭头(→ superclass)代表父类指针,虚线的箭头(→isa)代表isa指针,从上至下的深色方框依次代表:根类-> 父类-> 子类,从上至下每层的含义:
第一层:
isa指针: 根类的实例对象(instance Of Root class)的isa指向根类(Root class),根类的isa指针指向根元类(Root meta class),根元类的isa指向它本身。
superclass指针:根类(Root class)的superclass指向nil,根元类的父类指向根类。
第二层:
isa指针:父类的实例对象(instance of superclass)的isa指向父类(superclass),父类的isa指向父元类,父元类的isa指向根元类。
superclass指针:父类的superclass指向根类,父元类的superclass指向根元类。
第三层:
isa指针:子类实例对象(instance of subclass)的isa指向子类,子类的isa指向子元类,子元类的isa指向根元类。
superclass指针:子类的superclass指向父类,子元类的superclass指向父元类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 SubClass *subClassInstance = [SubClass new]; Class subClass = object_getClass(subClassInstance); Class subMetaClass = object_getClass(subClass); Class subMetaClassMetaClass = object_getClass(subMetaClass);
当发送消息给实例对象时,runtime函数会在此实例对象所属类的实例方法列表中查找方法实现(IMP)并调用,此为实例方法调用。
当发送消息给类对象时,runtime函数会在此实例对象所属类的元类的方法列表中查找方法实例(IMP)并调用,此为类方法调用。
NSObject NSObject 是大部分Objective-C类继承体系的根类。
OC runtime Runtime 中为我们提供了一系列 API 来获取 Class (类)的 成员变量( Ivar )、属性( Property )、方法( Method )、协议( Protocol ) 等。我们可以通过这些方法来遍历一个类中的成员变量列表、属性列表、方法列表、协议列表。
Runtime 的 API 都定义在 <objc/runtime.h> 中,函数的命名规则如下:
对对象进行操作的方法一般以object_开头
对类进行操作的方法一般以class_开头
对类或对象的方法进行操作的方法一般以method_开头
对成员变量进行操作的方法一般以ivar_开头
对属性进行操作的方法一般以property_开头开头
对协议进行操作的方法一般以protocol_开头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Class object_getClass(id obj) Class objc_getClass(const char *aClassName) Class objc_getMetaClass(const char *aClassName) Class class_getSuperclass(Class cls) BOOL class_isMetaClass(Class cls);
获取 Class 1 2 3 4 5 6 7 8 9 Class class = [instanceX class ]; Class class = [ClassX class ]; Class class = ClassX.class; Class class = NSClassFromString (@"ClassName" );
创建对象 1 2 id instance = [[class alloc] init];
方法调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SEL selector = NSSelectorFromString (@"FuncName" ); BOOL isNoParam = [instance respondsToSelector:@selector (MethodName_NoParam)];if (isNoParam) { [instance performSelector:@selector (MethodName_NoParam)]; } BOOL isOneParam = [instance respondsToSelector:@selector (MethodName_OneParam:)];if (isOneParam) { [instance performSelector:@selector (MethodName_OneParam:) withObject:@"first" ]; } BOOL isParams = [instance respondsToSelector:@selector (MethodName_Params: andParamSecond:)];if (isParams) { [instance performSelector:@selector (MethodName_Params: andParamSecond:) withObject:@"first" withObject:@"second" ]; }
获取类的成员变量 成员变量定义如下:
1 typedef struct objc_ivar *Ivar
成员变量有如下相关函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class_copyIvarList class_getInstanceVariable object_getIvar object_setIvar ivar_getName
获取类的属性 属性的定义:
1 typedef struct objc_property *objc_property_t;
属性有如下相关函数:
1 2 3 4 5 6 7 8 9 10 11 class_copyPropertyList property_getName property_getAttributes property_copyAttributeList
获取类的方法 方法的定义:
1 2 3 4 5 6 7 8 9 typedef struct objc_method *Method;struct objc_method { SEL _Nonnull method_name; char * _Nullable method_types; IMP _Nonnull method_imp; };
SEL 是一个指向 objc_selector 结构体的指针,其实是一个保存方法名的字符串。
IMP 的实质是一个函数指针,所指向的就是方法的实现。IMP用来找到函数地址,然后执行函数。
方法有如下相关函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class_copyMethodList class_getInstanceMethod(Class cls, SEL name) class_getClassMethod(Class cls, SEL name) class_getMethodImplementation(Class cls, SEL name) method_getName(Method m) method_getImplementation(Method m) method_getNumberOfArguments(Method m) method_copyArgumentType(Method m, unsigned int index) method_getReturnType(Method m, char * dst, size_t dst_len) method_getArgumentType(Method m, unsigned int index, char * dst, size_t dst_len) method_setImplementation(Method m, IMP imp) method_exchangeImplementations(Method m1, Method m2)
参考文档 https://juejin.cn/post/6912007846125273101 https://halfrost.com/objc_runtime_isa_class/ https://juejin.cn/post/6844903474908364808 https://www.jianshu.com/p/1fa5cf16c6db https://wjerry.com/2018/05/%E5%AF%B9%E8%B1%A1-%E7%B1%BB-%E5%85%83%E7%B1%BB-isa%E6%8C%87%E9%92%88%E4%B9%8B%E9%97%B4%E7%9A%84%E7%88%B1%E6%81%A8%E6%83%85%E4%BB%87/ https://zhangxiaom.github.io/2018/06/26/isa%E6%8C%87%E9%92%88%E4%B8%AD%E9%9A%90%E8%97%8F%E7%9A%84%E9%BB%91%E9%AD%94%E6%B3%95/