Objective-C消息转发探究

274 阅读3分钟
原文链接: blog.skytoup.com

概(fei)述(hua)

…(省略1024亿个byte)

探究

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

Test 0

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

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

      1234567891011121314151617181920212223242526272829303132
      @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
[[TestObject alloc] init];
  • 结果: 什么都没有log
  • 结论: 调用存在的方法, 没有发生任何消息转发

Test 1

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

    1. 代码

      12
      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

      123456789
      @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
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

      123456789
      @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
	- (void)testObject_1ExistsMethod {
   		NSLog(@"-->> %@ %p I am exists", [self class], self);
}
  • 结果: TestObject_2对象先调用了forwardingTargetForSelector:(返回TestObject_1对象), 然后TestObject_1对象调用了testObject_1ExistsMethod
  • 结论: 不存在的方法转发到了其它对象处理成功

Test 4

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

    1. 定义TestObject_3, 继承TestObject

      12345678910111213
      @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
TestObject_3* obj = [[TestObject_3 alloc] init];
  [obj performSelector:NSSelectorFromString(@"not exists sel")];
  • 结果: 先调用了forwardingTargetForSelector:, 然后methodSignatureForSelector:, 最后forwardInvocation:, 没发生崩溃
  • 结论: TestObject_3自己处理了不存在方法

总结

如下图
png

测试代码

TestMessageForwarding: github.com/skytoup/Tes…


本文为博主skytoup原创文章,未经博主skytoup允许不得转载。