美文网首页
Objective-C消息转发

Objective-C消息转发

作者: 凤栖林 | 来源:发表于2017-08-30 17:19 被阅读0次

    OC中调用方法就是向对象发送消息
    下面的代码:

     [self performSelector:@selector(method) withObject:nil];
    

    如果说method方法不存在,就会出现:unrecognized selector sent to instance
    从发送消息到崩溃中间经历了什么?
    首先分两种情况
    1,如果发送的是一个实例方法,会经过三个步骤
    第一步:

    + (BOOL)resolveInstanceMethod:(SEL)sel
    

    这个方法是实例方法未实现时自动执行,这个方法里面是让你在当前类里面对未实行的方法做弥补

    void dynamicMethodIMP(id sel,SEL _cmdd){
        NSLog(@"resolveInstanceMethod调用成功");
    }
    
    + (BOOL)resolveInstanceMethod:(SEL)sel{
        if (sel == @selector(method)) {
    //        class_addMethod([self class],sel,(IMP));
            class_addMethod([self class],sel,(IMP)dynamicMethodIMP, "v@:");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    
    

    第二步:
    如果第一步resolveInstanceMethod你没做处理,便会来到这一步,如果你处理了第一步,第二步是不会执行的

    - (id)forwardingTargetForSelector:(SEL)aSelector{
        if (aSelector == @selector(method)) {
            return [TestClass new];
        }
        return nil;
    }
    @implementation TestClass
    - (void)method{
        NSLog(@"method");
    }
    @end
    

    这一步是在其他类里面找对应的方法,所以TestClass里面必须要实现method方法,不然同样会崩溃
    第三步:
    经历过第一步,在本类中找弥补方法,第二步,在其他类中找弥补方法后,如果都没有找到,便会来到第三步

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
        NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
        if (!methodSignature) {
            methodSignature = [NSMethodSignature signatureWithObjCTypes:"v@:*"];
        }
        return methodSignature;
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
        testClass *messageForwarding = [testClass new];
        if ([messageForwarding respondsToSelector:anInvocation.selector]) {
            [anInvocation invokeWithTarget:messageForwarding];
        }
    }
    

    这一步实现方法的重新签名
    2.如果是调用了一个类方法,该类方法没有实现该怎么办
    便会调用resolveClassMethod

    void dynamicMethodIMP(id sel,SEL _cmdd){
        NSLog(@"resolveInstanceMethod调用成功");
    }
    @implementation testObject
    + (BOOL)resolveClassMethod:(SEL)sel{
      if (sel == @selector(hehe1)){
           class_addMethod(objc_getMetaClass("testObject"),sel,(IMP)dynamicMethodIMP, "v@:");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    @end
    

    看里面class_addMethod的第一个参数,是objc_getMetaClass("testObject"),该方法是获取当前类的元类,如果用[self class]是会崩溃的,因为dynamicMethodIMP是一个c方法,它是存在于元类里面的MessageList里面的,当前类找不到该方法,元类的知识可以看我另一篇文章:iOS类和元类关系
    如果resolveClassMethod方法没有实现,就会直接崩溃,也就是说它没有实例方法里面的第二步和第三步。
    resolveInstanceMethod和methodSignatureForSelector、forwardInvocation只是在实例方法缺失才会执行,类方法缺失不会执行,这点要注意

    相关文章

      网友评论

          本文标题:Objective-C消息转发

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