前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ios objc向一个对象发送消息时,发生了什么?

ios objc向一个对象发送消息时,发生了什么?

作者头像
赵哥窟
发布2018-09-13 11:44:18
1.7K0
发布2018-09-13 11:44:18
举报
文章被收录于专栏:日常技术分享日常技术分享
objc向一个对象发送消息时,发生了什么?

根据对象的isa指针找到该对象所属的类,去obj的对应的类中找方法 1.首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。 2.如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行 3.如果没找到,去父类指针所指向的对象中执行1,2. 4.以此类推,如果一直到根类还没找到,转向拦截调用,走消息转发机制。 5.如果没有重写拦截调用的方法,程序报错。

objc中向一个nil对象发送消息将会发生什么?

如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。也不会崩溃。

如果寻找不到相应的方法,会如何进行后续处理 ?

转向拦截调用。如果没有重写拦截调用的方法,程序报错。 拦截调用就是,在找不到调用的方法程序崩溃之前,你有机会通过重写NSObject的四个方法来处理。

方案一:

  • (BOOL)resolveInstanceMethod:(SEL)sel
  • (BOOL)resolveClassMethod:(SEL)sel 方案二:
  • (id)forwardingTargetForSelector:(SEL)aSelector 方案三:
  • (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
  • (void)forwardInvocation:(NSInvocation *)anInvocation;

1448535-f50463d32de94289.jpg

上图显示了消息转发的具体流程,接收者在每一步中均有机会处理消息。步骤越往后处理消息的代价越大。首先,会调用

  • (BOOL)resolveInstanceMethod:(SEL)sel。 若方法返回YES,则表示可以处理该消息。在这个过程,可以动态地给消息增加方法。
代码语言:javascript
复制
id ForwardingTarget_dynamicMethod(id self, SEL _cmd) {
    NSLog(@"没有找到方法:%@",NSStringFromSelector(_cmd));
    return [NSNull null];
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    class_addMethod(self.class, sel, (IMP)ForwardingTarget_dynamicMethod, "@@:");
    [super resolveInstanceMethod:sel];
    return YES;
}

调用

代码语言:javascript
复制
 People *people = [[People alloc] init];
 [people performSelector:@selector(speak)];

若方法返回NO,则进行消息转发的第二步,查找是否有其它的接收者。对应的处理函数是:

  • (id)forwardingTargetForSelector:(SEL)aSelector。 可以通过该函数返回一个可以处理该消息的对象。 现在新建一个类MsgForwarding,在MsgForwarding中实现一个speak方法. MsgForwarding.m
代码语言:javascript
复制
- (void)speak
{
    NSLog(@"MsgForwarding method speak called");
}

然后在People类中实现

代码语言:javascript
复制
- (id)forwardingTargetForSelector:(SEL)aSelector {

    NSString *selStr = NSStringFromSelector(aSelector);

    if ([selStr isEqualToString:@"speak"]) {
         // 这里返回MsgForwarding类对象,让MsgForwarding类去处理speak消息
        return [[MsgForwarding alloc] init];
    }

    return [super forwardingTargetForSelector: aSelector];
}

若第二步返回nil,则进入消息转发的第三步。调用 *- (void)forwardInvocation:(NSInvocation )anInvocation。

代码语言:javascript
复制
- (void)forwardInvocation:(NSInvocation *)anInvocation {
  
    SEL selector = [anInvocation selector];
    // 新建需要转发消息的对象
    MsgForwarding *msgForwarding = [[MsgForwarding alloc] init];
    if ([msgForwarding respondsToSelector:selector]) {
        // 唤醒这个方法
        [anInvocation invokeWithTarget:msgForwarding];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    if (aSelector == @selector(speak)) {
        return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

Demo:https://github.com/destinyzhao/MessageForwarding

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.08.17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • objc向一个对象发送消息时,发生了什么?
  • objc中向一个nil对象发送消息将会发生什么?
  • 如果寻找不到相应的方法,会如何进行后续处理 ?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档