blogger

skytoup's blog

分享经验, 共同进步; RSS: http://blog.skytoup.com/feed

文章44

分类0

评论0

Objective-C消息转发探究

概(fei)述(hua)

...(省略1024亿个byte)

探究

为了研究Objective-C的消息转发,做了一系列测试

Test 0

  • 内容: 调用对象存的方法
  • 步骤:

    1. 定义一个TestObject类,继承NSObject, 重写的方法如下:

      @implementation TestObject
      
      + (BOOL)resolveClassMethod:(SEL)sel {
          BOOL ret = [super resolveClassMethod:sel];
          NSLog(@"-->> %@ %p resolveClassMethod: %@, return: %d", [self class], self, NSStringFromSelector(sel), ret);
          return ret;
      }
      
      - (BOOL)respondsToSelector:(SEL)aSelector {
          BOOL ret = [super respondsToSelector:aSelector];
          NSLog(@"-->> %@ %p respondsToSelector: %@, return: %d", [self class], self, NSStringFromSelector(aSelector), ret);
          return ret;
      }
      
      - (id)forwardingTargetForSelector:(SEL)aSelector {
          id ret = [super forwardingTargetForSelector:aSelector];
          NSLog(@"-->> %@ %p forwardingTargetForSelector: %@, return: %@", [self class], self, NSStringFromSelector(aSelector), ret);
          return ret;
      }
      
      - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
          NSMethodSignature* ret = [super methodSignatureForSelector:aSelector];
          NSLog(@"-->> %@ %p methodSignatureForSelector: %@, return: %@", [self class], self, NSStringFromSelector(aSelector), ret);
          return ret;
      }
      
      - (void)forwardInvocation:(NSInvocation *)anInvocation {
          NSLog(@"-->> %@ %p forwardInvocation: %@", [self class], self, anInvocation);
          [super forwardInvocation:anInvocation];
      }
      
      @end
    2. 代码

      [[TestObject alloc] init];
  • 结果: 什么都没有log
  • 结论: 调用存在的方法, 没有发生任何消息转发

Test 1

  • 内容: 调用对象不存在的方法
  • 步骤:

    1. 代码

      TestObject* obj = [[TestObject alloc] init];
         [obj performSelector:NSSelectorFromString(@"not exists sel")];
  • 结果: TestObject调用了forwardingTargetForSelector:(返回nil), 然后调用methodSignatureForSelector:(返回nil), 最后log unrecognized selector sent to instance
  • 结论: 调用不存在的方法, 发生了消息转发

Test 2

  • 内容: TestObject_1重写forwardingTargetForSelector:(返回TestObject对象), 调用它们都不存在的方法
  • 步骤:

    1. 定义TestObject_1, 继承TestObject
    @implementation TestObject_1
    
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        id ret = [[TestObject alloc] init];
        NSLog(@"-->> %@ %p forwardingTargetForSelector: %@, return: %@", [self class], self, NSStringFromSelector(aSelector), ret);
        return ret;
    }
    
    @end
    1. 代码:
    TestObject_2* obj = [[TestObject_2 alloc] init];
       [obj performSelector:NSSelectorFromString(@"not exists sel")];
  • 结果: TestObject_1对象先调用了forwardingTargetForSelector:(返回TestObject对象), 然后TestObject对象调用forwardingTargetForSelector:(返回nil), 跟着调用methodSignatureForSelector:(返回nil), 最后log unrecognized selector sent to instance
  • 结论: 不存在的方法转发到了其它对象处理失败

Test 3

  • 内容: TestObject_2重写forwardingTargetForSelector:(返回TestObject_1), 调用TestObject_2不存在, 但TestObject_1存在的方法
  • 步骤:

    1. 定义TestObject_2, 继承TestObject
    @implementation TestObject_2
    
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        id ret = [[TestObject_1 alloc] init];
        NSLog(@"-->> %@ %p forwardingTargetForSelector: %@, return: %@", [self class], self, NSStringFromSelector(aSelector), ret);
        return ret;
    }
    
    @end
    1. TestObject_1, 添加方法
    - (void)testObject_1ExistsMethod {
           NSLog(@"-->> %@ %p I am exists", [self class], self);
    }
    1. 代码
    TestObject_2* obj = [[TestObject_2 alloc] init];
       [obj performSelector:NSSelectorFromString(@"testObject_1ExistsMethod")];
  • 结果: TestObject_2对象先调用了forwardingTargetForSelector:(返回TestObject_1对象), 然后TestObject_1对象调用了testObject_1ExistsMethod
  • 结论: 不存在的方法转发到了其它对象处理成功

Test 4

  • 内容: TestObject_3重写methodSignatureForSelector:(不返回nil)和forwardInvocation:, 调用不存在的方法
  • 步骤:

    1. 定义TestObject_3, 继承TestObject
    @implementation TestObject_3
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        NSLog(@"-->> %@ %p methodSignatureForSelector: %@", [self class], self, NSStringFromSelector(aSelector));
        return [NSObject methodSignatureForSelector:@selector(init)];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        NSLog(@"-->> %@ %p forwardInvocation: %@", [self class], self, anInvocation);
    //    [super forwardInvocation:anInvocation]; // will crash, because the method signature is not right
    }
    
    @end
    1. 代码
    TestObject_3* obj = [[TestObject_3 alloc] init];
       [obj performSelector:NSSelectorFromString(@"not exists sel")];
  • 结果: 先调用了forwardingTargetForSelector:, 然后methodSignatureForSelector:, 最后forwardInvocation:, 没发生崩溃
  • 结论: TestObject_3自己处理了不存在方法

总结

如下图
png

测试代码

TestMessageForwarding: https://github.com/skytoup/TestMessageForwarding

评论(0)

© 2020  skytoup's blog  · 由 Typecho 强力驱动
  Design by 往记