Runtime--Dynamic Method Resolution

Runtime–Dynamic Method Resolution

很多时候你想动态的提供方法的实现,比如说声明property的时候使用编译器指令@dynamic

@dynamic propertyName;

可以通过实现以下两个方法达到动态实现方法的目的

//如果找到方法实现并且添加到Class,则返回Yes,否则NO
//针对类方法
+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

//如果找到方法实现并且添加到Class,则返回Yes,否则NO
//针对实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

为了模拟场景,首先在新建工程的ViewController中声明但是不实现两个方法

@interface ViewController ()

-(void)ivarMethod;

+(void)classMethod;
@end

//此处会收到警告提示方法未实现
@implementation ViewController

然后定义两个对应的函数,Objective-C方法简单来说就是至少带有两个参数的C函数,这两个参数为selfand _cmd,代码如下

void ivar(id self,SEL _cmd)
{
    NSLog(@"调用ivar");
}

void class(id self,SEL _cmd)
{
    NSLog(@"调用class");
}

然后利用Runtime的class_addMethod函数给方法添加对应的implementation

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    if (sel == @selector(ivarMethod))
    {
        bool success = class_addMethod([self class], sel, (IMP)ivar, "v@:");
        return success;
    }
    return [super resolveInstanceMethod:sel];

}

+ (BOOL)resolveClassMethod:(SEL)sel
{
    if (sel == @selector(classMethod))
    {
        //此二者均可:object_getClass(self)、objc_getMetaClass("ViewController")
        bool success = class_addMethod(object_getClass(self), sel, (IMP)class, "v@:");
        return success;
    }
     return [super resolveClassMethod:sel];
}

最好调用方法完成动态添加实现

- (void)viewDidLoad 
{
[super viewDidLoad];
[self ivarMethod];
[ViewController classMethod];
}

//输出结果
调用ivar
调用class

看到输出结果表示动态添加效果已实现。

Message Forwarding 和 Dynamic method resolution

后者发生在前者之前。如果已经实现 resolveInstanceMethod:又想进行消息转发,那么这些方法都要返回NO(不要给方法添加实现)。下面通过代码来验证一下。
首先在以上代码的基础上重写消息转发必要的两个方法

//Data类中方法实现
-(void)ivarMethod
{
    NSLog(@"调用ivarMethod");
}

/***********分割线***********/
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSString *sel = NSStringFromSelector(anInvocation.selector);

    if ([sel isEqualToString:@"ivarMethod"])
    {   
        //消息转发到Data中
        [anInvocation invokeWithTarget:[[Data alloc] init]];
    }
    else
    {
        [super forwardInvocation:anInvocation];
    }
}


-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:selector];

     //生成方法签名
    if (! signature)
    {
        //处理不同的方法
        if (sel_isEqual(selector, @selector(ivarMethod)))
        {
            signature = [[[Data alloc] init] methodSignatureForSelector:selector];

        }

    }
    return signature;
}

然后resolveInstanceMethod:没有添加动态实现才能进行消息转发,否则直接执行了

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"resolveInstanceMethod");
    return [super resolveInstanceMethod:sel];
}

调用方法,通过打印结果顺序验证结果

- (void)viewDidLoad {
[super viewDidLoad];
[self ivarMethod];
}

//输出结果
resolveInstanceMethod
调用ivarMethod

forwardingTargetForSelector:

- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

1、当有unrecognized消息时,返回一个对象,以便消息可以转发。
2、如果一个对象继承或者实现了此方法,而且返回此对象,那么消息被成功转发调用
3、禁止返回self对象,否则引起死循环
4、对于不处理的方法,返回super’s implementation的结果
5、调用发生在forwardInvocation:之前;转发速度更快
6、不能够像NSInvocation那样操作返回值和参数
下边通过代码展示简单用法和验证执行顺序,在以上代码的基础上

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    NSLog(@"forwardingTargetForSelector");

    if (aSelector == @selector(ivarMethod))
    {
        return [[Data alloc] init];
    }
    else
    {
        return [super forwardingTargetForSelector:aSelector];
    }
}

/***********分割线***********/
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSString *sel = NSStringFromSelector(anInvocation.selector);
    //方法对比打印次序
    NSLog(@"forwardInvocation");

    if ([sel isEqualToString:@"ivarMethod"])
    {
        [anInvocation invokeWithTarget:[[Data alloc] init]];
    }
    else
    {
        [super forwardInvocation:anInvocation];
    }
}

调用变查看输出结果

- (void)viewDidLoad {
[super viewDidLoad];
[self ivarMethod];
}

//输出结果
resolveInstanceMethod       //Dynamic Method Resolution机制
forwardingTargetForSelector //消息转发
调用ivarMethod                //方法调用

通过结果可以看出处理 unrecognized messages的顺序:
1、Dynamic Method Resolution机制
2、- (void)forwardInvocation:(NSInvocation *)anInvocation
3、Message Forwarding
参考文献:Dynamic Method ResolutionNSObjectforwardingTargetForSelector:Message Forwarding

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值