美文网首页
iOS消息转发机制个人理解笔记

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

作者: 磊简单 | 来源:发表于2019-03-14 17:04 被阅读0次
    • 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消息转发机制个人理解笔记

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