基础知识

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

2018-08-17  本文已影响35人  赵哥窟
objc向一个对象发送消息时,发生了什么?

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

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

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

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

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

方案一:

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

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,则进行消息转发的第二步,查找是否有其它的接收者。对应的处理函数是:

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

上一篇 下一篇

猜你喜欢

热点阅读