iOS runtime随笔-消息转发机制
运行时的消息转发分三步, 当你调用了没有实现的方法时, 有机会通过runtime的消息转发机制补救一下
- resolveInstanceMethod/resolveClassMethod 这里可以动态去创建方法来解决Crash
- forwardingTargetForSelector 第一步未解决, 就会走到这里, 可以给出一个Target去转发这个消息(方法调用)
- forwardInvocation 上面2步都没有解决问题, 这里是最后一次机会, 利用methodSignatureForSelector返回一个方法签名, 在forwardInvocation中转发给对应的target
实例方法实现参考
+ (BOOL)resolveInstanceMethod:(SEL)sel {if (sel == @selector(testInstance)) {IMP imp = class_getMethodImplementation([self class], @selector(test));return class_addMethod([self class], sel, imp, "v@:");}return NO;
}- (id)forwardingTargetForSelector:(SEL)aSelector {if (aSelector == @selector(testInstance)) {return self.realObj;}return [super forwardingTargetForSelector:aSelector];
}- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {if (aSelector == @selector(testInstance)) {return [[RealTestObject alloc] methodSignatureForSelector:aSelector];}return [super methodSignatureForSelector: aSelector];
}- (void)forwardInvocation:(NSInvocation *)anInvocation {SEL sel = anInvocation.selector;if ([self.realObj respondsToSelector:sel]) {[anInvocation invokeWithTarget:self.realObj];return;}[super forwardInvocation:anInvocation];
}
类方法实现参考
+ (BOOL)resolveClassMethod:(SEL)sel {if (sel == @selector(testClass)) {
//也可以通过block创建一个IMP去替代方法实现
// IMP imp = imp_implementationWithBlock(^(void) {
// NSLog(@"imp_implementationWithBlock");
// });IMP imp = class_getMethodImplementation(objc_getMetaClass("TestObject"), @selector(testLogClass));class_addMethod(objc_getMetaClass("TestObject"), sel, imp, "v@:");return YES;}return NO;
}+ (id)forwardingTargetForSelector:(SEL)aSelector {if (aSelector == @selector(testClass)) {return [RealTestObject class];}return [super forwardingTargetForSelector:aSelector];
}+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {if (aSelector == @selector(testClass)) {return [RealTestObject methodSignatureForSelector:aSelector];}return [super methodSignatureForSelector:aSelector];
}+ (void)forwardInvocation:(NSInvocation *)anInvocation {SEL sel = anInvocation.selector;if (sel == @selector(testClass)) {[anInvocation invokeWithTarget:[RealTestObject class]];return;}[super forwardInvocation:anInvocation];
}