案例介绍
//MJPerson.h
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
- (void)test;
@end
//MJPerson.m
#import "MJPerson.h"
#import <objc/runtime.h>
#import "MJCat.h"
@implementation MJPerson
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
// objc_msgSend([[MJCat alloc] init], aSelector)
return [[MJCat alloc] init];
}
return [super forwardingTargetForSelector:aSelector];
}
@end
//MJCat.h
#import <Foundation/Foundation.h>
@interface MJCat : NSObject
- (void)test;
@end
//MJCat.m
#import "MJCat.h"
@implementation MJCat
- (void)test
{
NSLog(@"%s", __func__);
}
@end
//方法调用
MJPerson *person = [[MJPerson alloc] init];
[person test];
-
结果打印
-
person 只有方法声明没有test的实现
-
cat 有test方法的声明也有方法的实现
-
但是调用的时候通过forwardingTargetForSelector这个方法让person成功调用了cat里面的test方法
-
这个forwardingTargetForSelector方法也可以用下面的两个方法来代替
// 方法签名:返回值类型、参数类型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test)) {
return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
}
return [super methodSignatureForSelector:aSelector];
}
// NSInvocation封装了一个方法调用,包括:方法调用者、方法名、方法参数
// anInvocation.target 方法调用者
// anInvocation.selector 方法名
// [anInvocation getArgument:NULL atIndex:0]
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// anInvocation.target = [[MJCat alloc] init];
// [anInvocation invoke];
[anInvocation invokeWithTarget:[[MJCat alloc] init]];
}
- 当消息转发的方法是有传参和返回值得时候
//MJPerson.h
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
- (int)test:(int)age;
@end
//MJPerson.m
#import "MJPerson.h"
#import <objc/runtime.h>
#import "MJCat.h"
@implementation MJPerson
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if (aSelector == @selector(test:)) {
// return [NSMethodSignature signatureWithObjCTypes:"v20@0:8i16"];
return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
// return [[[MJCat alloc] init] methodSignatureForSelector:aSelector];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// 参数顺序:receiver、selector、other arguments
// int age;
// [anInvocation getArgument:&age atIndex:2];
// NSLog(@"%d", age + 10);
// anInvocation.target == [[MJCat alloc] init]
// anInvocation.selector == test:
// anInvocation的参数:15
// [[[MJCat alloc] init] test:15]
[anInvocation invokeWithTarget:[[MJCat alloc] init]];
int ret;
[anInvocation getReturnValue:&ret];
NSLog(@"%d", ret);
}
@end
//MJCat.h
#import <Foundation/Foundation.h>
@interface MJCat : NSObject
- (int)test:(int)age;
@end
//MJCat.m
#import "MJCat.h"
@implementation MJCat
- (int)test:(int)age
{
return age * 2;
}
@end
//方法调用
MJPerson *person = [[MJPerson alloc] init];
[person test:15];
- 当消息转发的方法类方法时
//MJPerson.h
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
+ (void)test;
@end
//MJPerson.m
#import "MJPerson.h"
#import <objc/runtime.h>
#import "MJCat.h"
@implementation MJPerson
+ (id)forwardingTargetForSelector:(SEL)aSelector
{
// objc_msgSend([[MJCat alloc] init], @selector(test))
// [[[MJCat alloc] init] test]
if (aSelector == @selector(test)) return [[MJCat alloc] init];
return [super forwardingTargetForSelector:aSelector];
}
//+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
//{
// if (aSelector == @selector(test)) return [NSMethodSignature signatureWithObjCTypes:"v@:"];
//
// return [super methodSignatureForSelector:aSelector];
//}
//
//+ (void)forwardInvocation:(NSInvocation *)anInvocation
//{
// NSLog(@"1123");
//}
@end
//MJCat.h
#import <Foundation/Foundation.h>
@interface MJCat : NSObject
+ (void)test;
- (void)test;
@end
//MJCat.m
#import "MJCat.h"
@implementation MJCat
+ (void)test
{
NSLog(@"%s", __func__);
}
- (void)test
{
NSLog(@"%s", __func__);
}
@end
//方法调用
[MJPerson test];
- 开发者可以在forwardInvocation:方法中自定义任何逻辑
- 以上方法都有对象方法、类方法2个版本(前面可以是加号+,也可以是减号-)
- 这个也有两种写法
- 个人认为消息转发机制也没有啥应用场景呀,了解就好了