IOS 动态方法解析和消息转发

  好的!今天我们来练习IOS,当消息发送给没有实现该消息方法的对象时,会开始消息转发流程:动态方法解析->寻找备用接收者->消息转发,要是这三个步骤都没有进行未实现方法的处理,会抛出异常。

动态方法解析

  首先我们暴露了Dog类的talk,callBaaBaa,callMeowMeow实例方法,但是Dog类没有实现这些方法,所以当dog对象调用它们就会奔溃,因此在resolveInstanceMethod方法中我们需要为dog对象添加talk实例方法(是人类的talk方法)。

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if([NSStringFromSelector(sel) isEqualToString:@"talk"]) {
        //因为狗类没有实现talk方法,在动态方法解析时为狗类增加说话的此方法
        class_addMethod([self class], @selector(talk), class_getMethodImplementation([Humanity class], @selector(talk)),  "v@:");
    }
    return [super resolveInstanceMethod:sel];
}
寻找备用接收者

  然后dog对象调用callBaaBaa方法,同样它没有实现该方法,也没有在resolveInstanceMethod中添加callBaaBaa方法,在调用完resolveInstanceMethod后,会进行forwardingTargetForSelector方法,因此我们在forwardingTargetForSelector寻找羊类作为callBaaBaa的备用接收者防止奔溃。

- (id)forwardingTargetForSelector:(SEL)aSelector {
    //备用接收者羊处理消息
    if([NSStringFromSelector(aSelector) isEqualToString:@"callBaaBaa"]) {
        return sheep;
    }
    return [super forwardingTargetForSelector:aSelector];
}
消息转发

  最后我们的dog对象调用了没有实现的callMeowMeow方法,当进行完forwardingTargetForSelector方法之后会调用forwardInvocation方法进行消息转发的处理,所以我们在forwardInvocation中将消息转发给猫类防止奔溃。

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL sel = [anInvocation selector];
    if([super respondsToSelector:sel]) {
        [super forwardInvocation:anInvocation];
    } else {
        [anInvocation invokeWithTarget:cat];//转发给猫类
    }
}

//重写methodSignatureForSelector,创建要转发的NSInvocation对象
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if([super respondsToSelector:aSelector]) {
        return [super methodSignatureForSelector:aSelector];
    } else {
        return [cat methodSignatureForSelector:aSelector];
    }
}

最后,完整代码链接:https://github.com/arrosev/CMDTestProject

你可能感兴趣的:(IOS 动态方法解析和消息转发)