专栏首页移动端周边技术扩展深入理解iOS消息转发机制

深入理解iOS消息转发机制

消息转发流程图

image

向一个对象发送消息时, 首先会在对象类的cache,method list以及父类对象的cache,method list依次查找SEL对应的IMP

如果没有找到,并且实现了动态方法决议机制就会决议。如果没有实现动态决议机制或者决议失败且实现了消息转发机制。就会进入消息转发流程。否则程序Crash.

进入消息转发 objc——msgSend(id, SEL,...)来实现消息转发

动态方法决议

字面上我的理解是:消息在发送过程中进行判断到底这消息该由谁接收

一:询问是否有动态添加方法来进行处理

Objective C 提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个 selector 提供实现。我们只要实现

+resolveInstanceMethod: 
+resolveClassMethod: 

并在其中为指定的 selector 提供实现即可(通过调用运行时函数 class_addMethod 来添加)。这两个方法都是 NSObject 中的类方法 实现

//People.m
void speak(id self, SEL _cmd){
    NSLog(@"Now I can speak.");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"resolveInstanceMethod:  %@", NSStringFromSelector(sel));
    if (sel == @selector(speak)) {
        class_addMethod([self class], sel, (IMP)speak, "V@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

+ (BOOL)resolveClassMethod:(SEL)name  
{  
    NSLog(@" >> Class resolving %@", NSStringFromSelector(name));  
      
    return [super resolveClassMethod:name];  
}

二:询问有没有别人能够帮忙处理一下

 - (id)forwardingTargetForSelector:(SEL)aSelector

使用如下

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"forwardingTargetForSelector:  %@", NSStringFromSelector(aSelector));
    Bird *bird = [[Bird alloc] init];
    if ([bird respondsToSelector:aSelector]) {
        return bird;
    }
    return [super forwardingTargetForSelector: aSelector];
}
// Bird.m
- (void)fly {
    NSLog(@"I am a bird, I can fly.");
}

三:在一和二中都没能处理掉时会进入

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
    if ([anInvocation selector] == @selector(code)) {
        Monkey *monkey = [[Monkey alloc] init];
        [anInvocation invokeWithTarget:monkey];
    }   
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
    if (aSelector == @selector(code)) {
        return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

END

最后消息未能处理的时候,还会调用到

- (void)doesNotRecognizeSelector:(SEL)aSelector

我们也可以在这个方法中做些文章,避免掉crash,但是只建议在线上环境的时候做处理,实际开发过程中还要把异常抛出来

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • UIBarButtonItem 位置问题

    程序员不务正业
  • node.js + express 后端项目小坑

    PROTOCOL_CONNECTION_LOST PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR

    程序员不务正业
  • Github第三方登录

    OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应...

    程序员不务正业
  • Java工具集-MD5加密工具

    cwl_java
  • Climbing Stairs

    问题:上楼每次能走一步或两步,有多少种走法 class Solution { public: int a[1000]; int dfs(int ...

    用户1624346
  • BZOJ3122: [Sdoi2013]随机数生成器(BSGS)

    直接把\(X_{i+1} = (aX_i + b) \pmod P\)展开,推到最后会得到这么个玩意儿

    attack
  • 洛谷P4063 [JXOI2017]数列(dp)

    这题想还是不难想的,就是写起来很麻烦,然后去看了一下loj的最短代码表示只能Orz

    attack
  • leetcode 一些算法题及答案

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

    WindWant
  • 力扣79——单词搜索

    单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

    健程之道
  • Async:简洁优雅的异步之道

    在异步处理方案中,目前最为简洁优雅的便是async函数(以下简称A函数)。经过必要的分块包装后,A函数能使多个相关的异步操作如同同步操作一样聚合起来,使其相互间...

    :::::::

扫码关注云+社区

领取腾讯云代金券