You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/* Use `Class` instead of `struct objc_class *` */
39
+
```
40
+
19
41
### SEL 与 IMP
20
42
43
+
SEL 可以将其理解为方法的 ID. 结构如下:
44
+
45
+
```objectivec
46
+
typedefstructobjc_selector *SEL;
47
+
48
+
structobjc_selector {
49
+
char *name; OBJC2_UNAVAILABLE;
50
+
char *types; OBJC2_UNAVAILABLE;
51
+
};
52
+
```
53
+
54
+
IMP 可以理解为函数指针,指向了最终的实现。
55
+
21
56
SEL 与 IMP 的关系非常类似于 HashTable 中 key 与 value 的关系。OC 中不支持函数重载的原因就是因为一个类的方法列表中不能存在两个相同的 SEL 。但是多个方法却可以在不同的类中有一个相同的 SEL,不同类的实例对象执行相同的 SEL 时,会在各自的方法列表中去根据 SEL 去寻找自己对应的IMP。这使得OC可以支持函数重写。
22
57
23
58
### 消息传递机制
@@ -26,9 +61,18 @@ SEL 与 IMP 的关系非常类似于 HashTable 中 key 与 value 的关系。OC
26
61
- 不涵盖消息cache机制
27
62
- 需要对Objective-C runtime有一定的了解
28
63
64
+
如下用于描述 objc_msgSend 函数的调用流程:
65
+
66
+
- 1.检测 SEL 是否应该被忽略
67
+
- 2.检测发送的 target 是否为 nil ,如果是则忽略该消息
68
+
-3.
69
+
- 当调用实例方法时,通过 isa 指针找到实例对应的 class 并且在其中的缓存方法列表以及方法列表中进行查询,如果找不到则根据 super_class 指针在父类中查询,直至根类(NSObject 或 NSProxy).
70
+
- 当调用类方法时,通过 isa 指针找到实例对应的 metaclass 并且在其中的缓存方法列表以及方法列表中进行查询,如果找不到则根据 super_class 指针在父类中查询,直至根类(NSObject 或 NSProxy). (根据此前的开篇中的图,Root Meta Class 还是有根类的。)
- 3.这步调用 methodSignatureForSelector 进行方法签名,这可以将函数的参数类型和返回值封装。如果返回 nil 说明消息无法处理并报错 `unrecognized selector sent to instance`,如果返回 methodSignature,则进入 forwardInvocation ,在这里可以修改实现方法,修改响应对象等,如果方法调用成功,则结束。如果依然不能正确响应消息,则报错 `unrecognized selector sent to instance`.
0 commit comments