iOS消息转发机制

作者: Eddiegooo | 来源:发表于2018-12-02 09:24 被阅读42次
iOS方法调用实际上就是消息转发过程

最简单的方法调用:

    [[MessageSend new] sendMessage:@"Hello"];
    //等同于
    //objc_msgSend([MessageSend new], @selector(sendMessage:), @"Hello");

开发过程中经常会遇到这个错误unrecognized selector sent to instance; 没有实现方法,或是方法没有找到,就直接崩溃了。

崩溃信息.png
实例:

调用一个方法:

[[MessageSend new] sendMessage:@"Hello"];

来看下具体怎么实现。
首先我不实现这个方法,来看下消息转发机制。

//实际上消息转发分为三个部分
//1.动态方法解析
//2.快速转发
//3.慢速转发
//4.消息未处理。
//越往下花费的代价越大。。


消息转发.png

1.动态方法解析

#import <objc/message.h>

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSString *method = NSStringFromSelector(sel);
    if ([method isEqualToString:@"sendMessage:"]) {
        return class_addMethod(self, sel, (IMP)sendIMP, "v@:@");
    }
    return NO;
}

void sendIMP(id self, SEL _cmd, NSString *msg) {
    NSLog(@"msg = %@", msg);
}

以上就是动态方法解析。

2.快速转发

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSString *method = NSStringFromSelector(aSelector);
    if ([method isEqualToString:@"sendMessage:"]) {
        //去找备胎类,看有没有实现这个方法
        return [SpareWheel new];
    }
    return [super forwardingTargetForSelector:aSelector];
}

这时候涉及到了另外一个类,看它有没有实现对应的方法。
如果有实现,消息转发结束。

3.慢速转发

//封装方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSString *method = NSStringFromSelector(aSelector);
    if ([method isEqualToString:@"sendMessage:"]) {
        //把这个方法存起来
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    }
    return [super methodSignatureForSelector:aSelector];

}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    //获得方法编号
    SEL sel = [anInvocation selector];
    //还来找备胎
    SpareWheel *sp = [SpareWheel new];
    //判断能否响应方法
    if ([sp respondsToSelector:sel]) {
        anInvocation.target = sp;
    }else {
        [super forwardInvocation:anInvocation];
    }
}

如果备胎类或是哪都找不到对应的实现方法,就会到这个方法里

-(void)doesNotRecognizeSelector:(SEL)aSelector {
    
}

作为找不到函数实现的最后一步,NSObject实现这个函数只有一个功能,就是抛出异常。
虽然理论上可以重载这个函数实现保证不抛出异常(不调用super实现),但是苹果文档着重提出“一定不能让这个函数就这么结束掉,必须抛出异常”。
在release 模式下我们可以尝试不让它抛出异常,这样就可以避免找不到方法崩溃了。 但是debug、还没上线时千万别这么做
假如你一定要这么做,可以这么写个分类:

@implementation NSObject (Message)

- (void)doesNotRecognizeSelector:(SEL)aSelector {
    if (DEBUG) {
        NSLog(@"这里有方法没实现,但是我就不让他崩溃");
    }
}

消息转发可以来兼容API。

NSInvocation 模块化、路由模式 解耦。

    //消息转发三种方法:
    //1. 直接调用
    MessageSend *send = [MessageSend new];
    [send sendMessage:@"Eddiegooo"];

    //2。perform 方法
    [send performSelector:@selector(sendMessage:) withObject:@"Eddiegooo"];
    //但是多个参数怎么办呢? 用三方法
    
    //3. NSInvocation
    NSMethodSignature *methodSign = [send methodSignatureForSelector:@selector(sendMessage:)];
    
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSign];
    [invocation setTarget:send];
    [invocation setSelector:@selector(sendMessage:)];
    NSString *string = @"Eddiegooo";
    [invocation setArgument:&string atIndex:2]; //这里为啥v从2开始?  IMP(self, _cmd, *) 传参都是在第三个才是。
    [invocation invoke];

NSInvocation 调用Block有点复杂,需要知道Block的底层源码。Aspects库参考。

相关文章

  • runtime系列文章总结

    《iOS Runtime详解(消息机制,类元对象,缓存机制,消息转发)》《消息转发机制与Aspects源码解析》《...

  • iOS理解Objective-C中消息转发机制附Demo

    iOS理解Objective-C中消息转发机制附Demo iOS理解Objective-C中消息转发机制附Demo

  • iOS面试-基础

    [toc] Runloop AutoReleasePool 多线程 响应者链 消息响应机制 消息转发机制 iOS内...

  • iOS 消息转发机制

    今天大概学习了下iOS的消息转发机制,还是挺有收获,在此做下笔记,以便后面温习。 1.iOS的消息转发机制原理如下...

  • iOS面试题总结(二)

    iOS面试题(二) 消息发送和转发机制,SEL和IMP 消息发送转载自黄龙辉消息发送和消息转发机制 在Object...

  • Runtime

    相关简单介绍 消息机制消息传递机制消息转发机制-动态添加方法消息转发机制-快速转发消息转发机制-慢速转发消息转发机...

  • iOS - 消息转发机制

    我们知道,OC是动态语言,所有的方法都会以消息的形式传递给对象,对象会根据方法的类型来进行实例方法或者类方法的选择...

  • 【iOS】消息转发机制

    1、动态方法解析 对象在收到无法处理的消息时,会调用下面的方法,前者是调用类方法时会调用,后者是调用对象方法时会调...

  • iOS消息转发机制

    OC消息转发 oc中的调用对象或者类不存在的方法,会执行一遍消息转发流程.消息转发主要包括4步 首先调用+ (BO...

  • iOS 消息转发机制

    iOS开发过程中我们经常会碰到这样的报错:unrecognized selector sent to instan...

网友评论

    本文标题:iOS消息转发机制

    本文链接:https://www.haomeiwen.com/subject/wshaqqtx.html