美文网首页基础知识
ios objc向一个对象发送消息时,发生了什么?

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

作者: 赵哥窟 | 来源:发表于2018-08-17 14:42 被阅读35次
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,则表示可以处理该消息。在这个过程,可以动态地给消息增加方法。
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;
}

调用

 People *people = [[People alloc] init];
 [people performSelector:@selector(speak)];

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

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

然后在People类中实现

- (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。

- (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

相关文章

网友评论

    本文标题:ios objc向一个对象发送消息时,发生了什么?

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