iOS消息传递和消息转发机制

徘徊边缘 提交于 2020-01-31 05:40:51

我一直搞不清楚,方法method和selector(选择子)到底是啥关系,通过百度
在 Objective-C 中,selector,Method 和 implementation(IMP) 都是 Runtime 的组成部分。在实际开发中它们常常是可以相互转换来处理消息的发送的。选择子代表方法在 Runtime 期间的标识符。为 SEL 类型,虽然 SEL 是 objc_selector 结构体指针,但实际上它只是一个 C 字符串。在类加载的时候,编译器会生成与方法相对应的选择子,并注册到 Objective-C 的 Runtime 运行系统。
得出结论:

选择子其实是方法的名称,不同类中方法名相同参数不同的俩个方法,他们的选择子是相同的。

来看看Method的结构体

/// Method
struct objc_method {
    SEL method_name; 
    char *method_types;
    IMP method_imp;
};
  • 方法名 method_name 类型为 SEL,前面提到过相同名字的方法即使在不同类中定义,它们的方法选择器也相同。
  • 方法类型 method_types 是个 char 指针,其实存储着方法的参数类型和返回值类型,即是 Type Encoding 编码。(即类型编码)
  • method_imp 指向方法的实现,本质上是一个函数的指针,就是前面讲到的 Implementation。

不知道大家有没有用过 (IMP)。

下面让我们来看看这个方法:

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

这个方法主要接受四个参数

Class cls 要添加方法的类

SEL name 被添加方法的名字

IMP imp 添加的方法的实现

const char *types 描述方法参数类型的字符数组。

注意这个 IMP,如果你只是简单写了一个方法,像这样:
在这里插入图片描述
这个IMP是代表函数指针,即函数执行的入口。我们的方法的函数形式是

void method(id self, SEL _cmd);

默认俩个参数是方法调用者和方法名,看到了吗,这个SEL类型其实只是名字而已。
以上为 selector,Method 和 implementation(IMP) 的内容。

消息传递机制

Objective-C 语言 中,对象方法调用都是类似 [receiver selector]; 的形式,其本质就是让对象在运行时发送消息的过程。
c语言是静态绑定的语言,也就是在编译时就能觉得运行时你会调用什么函数,而OC是动态绑定。
让我们看看消息的流程
在这里插入图片描述
粘贴自不羁阁。
最后一条,临时添加对应的实现方法也在这个消息转发的过程中
所有 Objective-C 方法调用在编译时都会转化为对 C 函数 objc_msgSend 的调用。objc_msgSend(receiver,selector); 是 [receiver selector]; 对应的 C 函数。

消息转发机制

当我们在.h文件中写了一个方法,但是却没写实现,你会发现你可以调用这个方法,编译器在编译器不会报错,它相信在运行期可以找到方法实现,因为你没写,所以在运行的时候会崩。
当对象收到无法解读的消息后,首先将调用其所属类的一个方法

+ (BooL)resolveInstanceMethod:(SEL)sel

这里的sel就是我们刚刚调用的方法,应该叫选择子。这个方法表示这个类能否新增一个实例方法用来处理这个选择子,在继续向下执行转发机制之前,本类有机会新增一个处理此选择子的方法。

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *selectorString = NSStringFromSelector(sel);
    Method method = class_getInstanceMethod([self class], @selector(rush));
    if ([selectorString isEqualToString:@"rushB"]) {
        class_addMethod(self, sel, method_getImplementation(class_getInstanceMethod([self class], @selector(rush))), method_getTypeEncoding(method));
        return YES;
    }

1.第一步首先将这个选择子转成字符串
2.第二步是为了获取他的type coding。前面写过这个class_addMethod.它有4个参数:

Class cls 要添加方法的类

SEL name 被添加方法的名字

IMP imp 添加的方法的实现

const char *types 描述方法参数类型的字符数组。

我们可以用查表的方式填写第四个参数,也可以用这个方法。

还有俩个方法都是将消息的接受者转移。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!