Runtime-消息转发详解

 

消息转发分为三步,详细分解如下:

第一步

+ (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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值