关于IOS的消息转发

简单描述就是:

消息转发就是实例对象或者类调用了方法后,都会转化成objc_msgSend的方式,给方法调用者发送了一条selector消息,通过isa查找类或父类的方法列表,如褁没有找到对应的方法,则通过动态方法解析和消息转发来补救,还不行则会crash。

objc_msgSend具体还包含三个步骤:

1.消息发送:

在当前类或父类中查找方法,找到则存储他的imp(指向方法实现的指针);

2.动态方法解析:

如褁消息发送没有找到对应方法,则动态方法解析器开始工作,先判断当前cls对象是不是元类,也就是如果是对象方法会走到_class_resolveInstanceMethod,如过是类对象则会执行_class_resolveClassMethod,如过到最后没有查到,NSObject的resolveInstanceMethod会返回NO。

#pragma mark - 动态方法解析 
#比如有个run 方法没有声明和实现,增加方法后就不会出现找不到方法崩溃的问题了。
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"动态方法解析 - %@",self);
    if (sel == @selector(run)) {
        // 我们动态解析对象方法
        NSLog(@"对象方法 run 解析走这里");
        SEL readSEL = @selector(readBook);
        Method readM= class_getInstanceMethod(self, readSEL);
        IMP readImp = method_getImplementation(readM);
        const char *type = method_getTypeEncoding(readM);
        return class_addMethod(self, sel, readImp, type);
    }
    return [super resolveInstanceMethod:sel];
#此时只是给对象方法添加了一个imp,接下来再次进入查找imp流程,重复之前的操作,只不过现在对象方法已经有了imp,就会返回imp后继续执行
3.消息转发;

消息转发就是对方法进行替换了,具体可以看看https://www.jianshu.com/p/4f211020de05
,说明挺详细,能实现一些黑魔法的方式,比如里面提到的message的.m来实现VC的方法,这样可以提供.M给用户,但是重点方法保护起来。

补充一点:runtime如何通过selector找到对应的IMP地址?

每一个类对象中都一个对象方法列表(对象方法缓存)
类方法列表是存放在类对象中isa指针指向的元类对象中(类方法缓存)。
方法列表中每个方法结构体中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现。
当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找。
当我们发送一个消息给一个类时,这条消息会在类的Meta Class对象的方法列表里查找。

总结起来就是,类方法和对象方法都会存储成一个方法列表,通过selector方法用方法的名字来查找对应的实现。

你可能感兴趣的:(关于IOS的消息转发)