> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/ios/runtime/runtime-xiao-xi-ji-zhi.md).

# 03.消息机制

> `OC`中调用方法称为`消息传递` `OC`中消息传递采用动态绑定机制来决定具体调用哪个方法,但`OC`不是在编译时决定调用什么方法而是在运行时决定

## 转换为CPP

将`.m`转换为`.cpp`的`clang`命令

```
clang -rewrite-objc xxx.m
```

* OC

```
int main(int argc, const char * argv[]) {
@autoreleasepool {
     //为了方便查看转写后的C语言代码，将alloc和init分两步完成
    Person *p = [Person alloc];
    p = [p init];
    p.name = @"Jiaming Chen";
    [p showMyself];
  }
  return 0;
}
```

* CPP

```
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;

    Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc"));
    p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("init"));
    ((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)p, sel_registerName("setName:"), (NSString *)&__NSConstantStringImpl__var_folders_1f_dz4kq57d4b19s4tfmds1mysh0000gn_T_main_f5b408_mi_1);
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("showMyself"));

   }
  return 0;
}
```

* 调用方法时具体发生了什么呢?
* 现在本类的方法缓存列表中寻找有没有对应方法,如果有就执行
* 如果没有缓存的,就在本类的犯法列表中查找,找到了就执行
* 如果没找到,就到父类中查找,找到了就执行
* 没找到,进入下面的流程

### 消息处理-ResolveMethod

1. 如果沿继承树没有找到相关方法则会向接受者所属的类进行一次请求,看能否动态添加一个方法
2. 在相应的类及父类中找不到方法实现的话会执行`+ (BOOL)resolveInstanceMethod:(SEL)sel`这个方法,如果没重写的话会返回`NO`
3. 在该方法中我们可以为找不到实现的`SEL`添加一个实现.这样就能防止调用一个不存在的方法时崩溃.

### 消息单项转发

1. 当`resolveInstanceMethod`返回`NO`,就会进入消息转发阶段`- (id)forwardingTargetForSelector: (SEL)aSelector`
2. 该方法会返回一个累的对象,该对象包含`SEL`对应的实现.如果返回`nil`或`self`的话说明找不到相应的转发进入下一步

### 消息多项转发

> 如果不将消息转发给其他对象就只能自己处理或者崩溃了

#### - (NSMethodSignature \*)methodSignatureForSelector:(SEL)aSelector

* 获取方法的参数及返回数据类型,也就是说获取的是该方法的签名并返回,进入下一步
* 返回`NSMethodSignature`为`nil`的话不会进入下一步,抛出异常

> 具体的实现方式不再展开, 每种数据类型都有对应的符号代表,根据一定规则生成描述

#### - (void)forwardInvocation:(NSInvocation \*)anInvocation

* `runtime`将要转发的消息封装为`NSInvocation`调用`- (void)forwardInvocation: (NSInvocation*)invocation;`
* 在这个函数里可以将NSInvocation多次转发到多个对象中
* 调用这个方法如果不能处理就会调用父类的相关方法,一直到`NSObject`的这个方法
* 如果`NSObject`都无法处理就会调用`doesNotRecognizeSelector:`方法抛出异常

> `NSInvocation`有点类似于`java`里的反射，它有一套完整的装备：`target`，`selector`，`returnValue`，`ArgumentArray`，有了它们，`NSInvocation`就可以动态的`invoke`任意对象的任意方法了。

## 参考

<https://www.jianshu.com/p/a4a7e91d38f3>
