objective-c 消息重定向 之 动态解析机制

我们在上篇文章中提到,要处理 obj 找不到 对应的 方法的时候,有3种方法可以处理,从而不让系统crash.

这第一种方法就是 动态解析机制。主要函数为 

+ (BOOL) resolveInstanceMethod:(SEL)sel

//IMP 函数, obj 表示 self, _cmd 表示当前方法
void DogBark(id obj, SEL _cmd, id content) {
    NSLog(@"The Dog is Barking: %@", content);
}

+ (BOOL) resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(Bark)) {
        class_addMethod([self class], sel, (IMP)(DogBark), "v@:@");
        //v@:@ 表示是void 类型函数,后面接一个 参数
        return YES;
    }
    else {
        return [super resolveInstanceMethod:sel];
    }
}

 示例方法如下:

比如我们调用 Bark 方法,其实 Bark 方法并没有在我们的类中提供。但是我们提供了IMP 叫 DogBark , 在动态解析的过程中,我们把 对Bark的调用, 替换为 对DogBark 这个IMP的调用。

[self performSelector:@selector(Bark) withObject:@"555"];

为什么用 performSelector 呢,因为 如果直接写 [self Bark] 会编译不通过,编译器的自动检查机制会直接不让你调用没有定义的方法。所以这里是动态调用。

然后我们可以看到, 对 Bark的调用,成功动态解析为了 对 DogBark 这个 IMP的调用。

如果我们有动态解析,那么返回 TRUE, 否则, 返回 super的实现。

 

 下面我们研究下 

class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,

                const char * _Nullable types)  这个函数,这个函数用来动态给 一个类 的 name 方法 添加 一个IMP 实现。

最后一个参数,表示 IMP的类型,  V@:  表示 返回值为 Void, 参数为空。    V@:@ 表示 返回值为Void, 参数为 一个 obj, 详见 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1

另外我们看下 class_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name) 这个函数,这个函数表示我们获得 一个类的 selector 的 IMP run time 函数。

 

看看下面的代码会发生什么?分别定义 Dog  和 Pig 两个类,其中 Dog 类没有任何方法, 而 Pig 类有一个 Bark 方法。

@interface Dog : NSObject

@end


@implementation Dog

@end
@interface Pig : NSObject

-(void) Bark;

@end


@implementation Pig

-(void) Bark {
    NSLog(@"Pig is Barking");
}

@end

 然后我们把 Pig 类的 Bark 的IMP 实现, 动态绑定到 Dog 的 Bark 方法上,看看结果是什么呢?

    class_addMethod([Dog class], @selector(Bark), class_getMethodImplementation([Pig class], @selector(Bark)), "v@:");
    
    Dog * myDog = [[Dog alloc] init];
    [myDog performSelector:@selector(Bark)];

神奇的事情发送了, 我们调用Dog 的 Bark 方法, 但是实际上执行的却是 Pig 的 Bark 方法。 

 

我们再来看看 

class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp,

                    const char * _Nullable types)   这个函数,

顾名思义, 我们直接把 Dog 的 Bark 函数 替换为  Pig 的 Bark IMP实现, 也可以实现我们同样的效果。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值