概(fei)述(hua)
...(省略1024亿个byte)
探究
为了研究Objective-C的消息转发,做了一系列测试
Test 0
- 内容: 调用对象存的方法
步骤:
定义一个
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代码
[[TestObject alloc] init];
- 结果: 什么都没有log
- 结论: 调用存在的方法, 没有发生任何消息转发
Test 1
- 内容: 调用对象不存在的方法
步骤:
代码
TestObject* obj = [[TestObject alloc] init]; [obj performSelector:NSSelectorFromString(@"not exists sel")];
- 结果:
TestObject调用了forwardingTargetForSelector:(返回nil), 然后调用methodSignatureForSelector:(返回nil), 最后logunrecognized selector sent to instance - 结论: 调用不存在的方法, 发生了消息转发
Test 2
- 内容:
TestObject_1重写forwardingTargetForSelector:(返回TestObject对象), 调用它们都不存在的方法 步骤:
- 定义
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- 代码:
TestObject_2* obj = [[TestObject_2 alloc] init]; [obj performSelector:NSSelectorFromString(@"not exists sel")];- 定义
- 结果:
TestObject_1对象先调用了forwardingTargetForSelector:(返回TestObject对象), 然后TestObject对象调用forwardingTargetForSelector:(返回nil), 跟着调用methodSignatureForSelector:(返回nil), 最后logunrecognized selector sent to instance - 结论: 不存在的方法转发到了其它对象处理失败
Test 3
- 内容:
TestObject_2重写forwardingTargetForSelector:(返回TestObject_1), 调用TestObject_2不存在, 但TestObject_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- TestObject_1, 添加方法
- (void)testObject_1ExistsMethod { NSLog(@"-->> %@ %p I am exists", [self class], self); }- 代码
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:, 调用不存在的方法 步骤:
- 定义
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- 代码
TestObject_3* obj = [[TestObject_3 alloc] init]; [obj performSelector:NSSelectorFromString(@"not exists sel")];- 定义
- 结果: 先调用了
forwardingTargetForSelector:, 然后methodSignatureForSelector:, 最后forwardInvocation:, 没发生崩溃 - 结论:
TestObject_3自己处理了不存在方法
总结
如下图
测试代码
TestMessageForwarding: https://github.com/skytoup/TestMessageForwarding