iOS消息转发机制个人理解笔记

  • iOS开发过程中,有一类的错误会经常遇到,就是找不到所调用的方法,当然这类问题比较好解决,给当前对象或其父类对象添加该方法即可,使得编译器在编译时能正确找到该方法;或者,还有另外的方法,由于Objective-C是一门动态语言,我们也可以在运行期再给类添加该方法,一样可以解决该问题,而这就涉及了类的消息转发机制。
image

上图为消息转发全部流程,分为三步,感觉是一种递进式,倒不是能做到的事情递进,是想让你做的事递进发展。比如第一步动态的添加一个方法,第二步重新选择个对象作为接收者,如果第一步第二步你都不选择,那么你可能需要一个更全面的转发方式。

    Person *person = [Person new];
    // 调用Person类对象的needDo方法
    [person performSelector:@selector(needDo)];

如果Person类不实现needDo 方法就会报错。

2019-03-14 16:36:46.833003+0800 Test[4424:39573] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person needDo]: unrecognized selector sent to instance 0x600001bf8a00'

这样就可以用到消息转发化解掉这个报错。

第一步

动态添加方法

可以通过重写以下两个方法

// 处理类方法转发
+ (BOOL)resolveClassMethod:(SEL)sel{
    return NO;
}
// 处理实例方法转发
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    return NO;
}

具体做法:

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSString *selStr = NSStringFromSelector(sel);
    if ([selStr isEqualToString:@"needDo"]){
        class_addMethod(self, sel, (IMP)iDothis, "v@:");
        //这里YES和NO效果一样 我也不知道为啥
        return YES;
    }
    return NO;
}
void iDothis(){
    printf("第一步转发 do");
}

第二步

重新选择接受对象

- (id)forwardingTargetForSelector:(SEL)aSelector{
    NSString *selStr = NSStringFromSelector(aSelector);
    if ([selStr isEqualToString:@"needDo"]){
        // PersonSon 类实现needDo方法
        return [PersonSon new];
    }
    return nil;
}

第三步

最后一步 完整的消息转发

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSString *selStr = NSStringFromSelector(aSelector);
    if ([selStr isEqualToString:@"needDo"]){
        return [NSMethodSignature signatureWithObjCTypes:"v@:@@"];
    }
    return nil;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
    NSString *sleep = @"sleep";
    NSString *work = @"work";
    [anInvocation setTarget:self];
    [anInvocation setArgument:&sleep atIndex:2];
    [anInvocation setArgument:&work atIndex:3];

    [anInvocation setSelector:@selector(toSleep:or:)];
    [anInvocation invoke];
}
- (void)toSleep:(NSString*)sleep or:(NSString*)work{
    NSLog(@"just %@ or %@",sleep,work);
}

你可能感兴趣的:(iOS消息转发机制个人理解笔记)