消息转发分为三步,详细分解如下:
第一步
+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
第二步
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
第三步
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
首先来看看第一步,都是类方法,也就是在类方法层面来解决转发,有2个方法,第一个为解决类方法的转发,第二个为解决实例方法的转发,我们会分别举例说明,首先定义个类
///.h
@interface MessageForwarding : NSObject
@end
///.m
#import "MessageForwarding.h"
#import <objc/runtime.h>
void TestMsgForwardingIMP(id obj,SEL sel){
NSLog(@"success1");
}
@implementation MessageForwarding
+(BOOL)resolveClassMethod:(SEL)sel{
const char *selName = sel_getName(sel);
if (strcmp(selName, "TestMsgForwarding") == 0) {
class_addMethod([self superclass], sel, [self methodForSelector:@selector(TestMsgForwardingIMP1)], "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
+(void)TestMsgForwardingIMP1{
NSLog(@"success");
}
@end
在上面类的方法里面,我们可以看到class_addMethod方法,那么我们先看下官方稳定里面怎么定义的
/**
* Adds a new method to a class with a given name and implementation.
*
* @param cls The class to which to add a method.
* @param name A selector that specifies the name of the method being added.
* @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.
* @param types An array of characters that describe the types of the arguments to the method.
*
* @return YES if the method was added successfully, otherwise NO
* (for example, the class already contains a method implementation with that name).
*
* @note class_addMethod will add an override of a superclass's implementation,
* but will not replace an existing implementation in this class.
* To change an existing implementation, use method_setImplementation.
*/
OBJC_EXPORT BOOL
class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,
const char * _Nullable types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
现在咱们看下执行代码和结果
[MessageForwarding performSelector:@selector(TestMsgForwarding)];
打印结果如下:
OCTest[11268:1533041] success
切换成TestMsgForwardingIMP(C的方式)这个定义
#import "MessageForwarding.h"
#import <objc/runtime.h>
void TestMsgForwardingIMP(id self,SEL sel){
NSLog(@"success1");
}
@implementation MessageForwarding
+(BOOL)resolveClassMethod:(SEL)sel{
const char *selName = sel_getName(sel);
if (strcmp(selName, "TestMsgForwarding") == 0) {
// class_addMethod([self superclass], sel, [self methodForSelector:@selector(TestMsgForwardingIMP1)], "v@:");
class_addMethod([self superclass], sel, (IMP)TestMsgForwardingIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
+(void)TestMsgForwardingIMP1{
NSLog(@"success");
}
@end
继续执行结果如下:
OCTest[11416:1558454] success1
实例方法的转发,代码如下:
+(BOOL)resolveInstanceMethod:(SEL)sel{
const char *selName = sel_getName(sel);
if (strcmp(selName, "testInstanceMsgForwarding") == 0) {
class_addMethod(self, sel,[self instanceMethodForSelector:@selector(testInstanceMsgForwardingIMP)], "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
-(void)testInstanceMsgForwardingIMP{
NSLog(@"instance success");
}
调用代码如下
MessageForwarding *mf = [MessageForwarding new];
[mf performSelector:@selector(testInstanceMsgForwarding)];
执行结果如下:
OCTest[11656:1582545] instance success
第二步
修改函数的执行对象,代码如下:
#import "MessageForwarding.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self performSelector:@selector(testInstanceMsgForwarding)];
}
-(id)forwardingTargetForSelector:(SEL)aSelector{
if (strcmp(sel_getName(aSelector), "testInstanceMsgForwarding") == 0) {
return [MessageForwarding new];
}
return [super forwardingTargetForSelector:aSelector];
}
@end
执行结果如下:
OCTest[11702:1587797] instance success
第三步
随意指定对象执行相应函数,代码如下:
#import "MessageForwarding.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self performSelector:@selector(testInstanceMsgForwarding)];
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (strcmp(sel_getName(aSelector), "testInstanceMsgForwarding") == 0){
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
MessageForwarding *mf = [MessageForwarding new];
if ([mf respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:mf];
}else{
[self doesNotRecognizeSelector:anInvocation.selector];
}
}
@end
执行结果如下:
OCTest[11778:1594036] instance success