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];

// 编译时 RunTime 会将上述代码转化成发送消息
objc_msgSend(receiver, @selector(message));

// ================ performSelector ===============
// 先判断对象是否能调用方法,再执行调用方法
if ([receiver respondsToSelector:@selector(message)]) {
// 调用无参无返回值方法
[receiver performSelector:@selector(message)];
}
  • 编译阶段:[receiver selector]; 方法被编译器转换为: objc_msgSend(recevier,selector,org1,org2,…)
  • 运行时阶段:消息接受者 recever 寻找对应的 selector。
    1. 通过 recevier 的 isa 指针 找到 recevier 的 Class(类);
    2. 在 Class(类) 的 cache(方法缓存) 的散列表中寻找对应的 IMP(方法实现);
    3. 如果在 cache(方法缓存) 中没有找到对应的 IMP(方法实现) 的话,就继续在 Class(类) 的 method list(方法列表) 中找对应的 selector,如果找到,填充到 cache(方法缓存) 中,并返回 selector;
    4. 如果在 Class(类) 中没有找到这个 selector,就继续在它的 superClass(父类)中寻找;一旦找到对应的 selector,直接执行 recever 对应 selector 方法实现的 IMP(方法实现)。
    5. 若找不到对应的 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>

// OC1.0 class 结构体定义
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;
/* Use `Class` instead of `struct objc_class *` */

// OC2.0 class 结构体定义,我们注意到上面的定义后面的标识符OBJC2_UNAVAILABLE,意思是已经不适用ObjC2.0了,现在ObjC2.0 对objc_class的定义如下:
struct objc_class : objc_object {
isa_t isa;
Class superclass;
cache_t cache;
class_data_bits_t bits;
};

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
  • isa:是一个不能为空(null)的Class对象,它指向自己的创建者(类或元类)。
  • super_class:是一个可以为空的Class对象,它指向当前类的父类。
  • ivars:是实例变量列表,保存着该类的所有实例变量。
  • methodLists:是方法列表,保存着实例方法和类方法。
  • protocols:是协议列表,保存该类的协议方法。
  • cache:是一个缓存,用于缓存最近使用过的方法。

OC Object

1
2
3
4
5
6
7
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;

一个 Object(对象)唯一保存的就是它所属 Class(类) 的地址。

OC 实例对象、类、元类关系

  1. instance 实例对象是由类创建出来的对象,根据实际情况,内存中存在多份。实例对象通过isa指针指向类(对象)。
  2. class 类是实例对象的描述,保存了实例对象的定义。同时,类也是元类的对象(类对象),内存中只有一份。类对象通过isa指针指向元类(对象)。
  3. metaclass 元类是类对象的描述。元类对象的isa指针指向根元类,即由根元类创建的元类。根元类的isa指针指向自己,形成一个封闭的内循环。

OC 对象-类-元类继承关系

实线的箭头(→ 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 -> SuperClass -> NSObject

SubClass *subClassInstance = [SubClass new]; // 实例对象
Class subClass = object_getClass(subClassInstance); // 类对象
Class subMetaClass = object_getClass(subClass); // 元类对象
Class subMetaClassMetaClass = object_getClass(subMetaClass); // 元类对象的元类对象

// 1. 实例对象的 isa 指针指向类对象: subClass = [SubClass class]
// 2. 类对象的 isa 指针指向元类对象: subMetaClass = objc_getMetaClass("SubClass")
// 3. 元类对象的 isa 指针指向根元类(NSObject元类): subMetaClassMetaClass = objc_getMetaClass("NSObject")
// 4. 根元类(NSObject元类)的 isa 指针指向自己: objc_getMetaClass("NSObject") = object_getClass(objc_getMetaClass("NSObject"))
// 5. 子类的元类的父类指向父类的元类: class_getSuperclass(objc_getMetaClass("SubClass")) = objc_getMetaClass("SuperClass")
// 6. NSObject的父类为nil: class_getSuperclass([NSObject class]) = nil
// 7. 根元类(NSObject元类)的父类指向NSObject: class_getSuperclass(objc_getMetaClass("NSObject")) = [NSObject class]

OC对象-类-元类之间的关系

  • 当发送消息给实例对象时,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
/*
传入 instance 对象,返回 class 对象
传入 class 对象,返回 meta-class 对象
传入 meta-class 对象,返回 NSObject 基类的 meta-class 对象
*/
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
// 通过 class 创建对象 
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
/// An opaque type that represents a method in a class definition.
/// 代表类定义中一个方法的不透明类型
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

// Returns a specified instance method for a given class.
class_getInstanceMethod(Class cls, SEL name)

// Returns a pointer to the data structure describing a given class method for a given class.
class_getClassMethod(Class cls, SEL name)

// Returns the function pointer that would be called if a particular message were sent to an instance of a class.
class_getMethodImplementation(Class cls, SEL name)

// 获取方法名
method_getName(Method m)

// Returns the implementation of a method.
method_getImplementation(Method m)

// Returns the number of arguments accepted by a method.
method_getNumberOfArguments(Method m)

// Returns a string describing a single parameter type of a method.
method_copyArgumentType(Method m, unsigned int index)

// Returns by reference a string describing a method's return type.
method_getReturnType(Method m, char * dst, size_t dst_len)

// Returns by reference a string describing a single parameter type of a method.
method_getArgumentType(Method m, unsigned int index, char * dst, size_t dst_len)

// Sets the implementation of a method.
method_setImplementation(Method m, IMP imp)

// Exchanges the implementations of two methods.
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/