runtime交换方法的正确姿势

runtime交换方法的正确姿势

说到Objective-C大家就会想到黑魔法runtime,(不知道runtime是什么的看这里,runtime是开源的,源码在这里),本文主要讲解如何利用runtime正确的交换方法,将会提到两种方式去交换,以及我们在什么情况下改怎么去用。

我们知道OC的方法到了runtime就被体现成结构体

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}

要交换方法的话,无非也就是下面两个方法:

OBJC_EXPORT IMP method_setImplementation(Method m, IMP imp) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

我们通常同的估计也就是第二种方法吧,下面我们来看看用第二种方法存在什么样的问题,我们假设有这么两个方法:

Method m1 { 

      SEL method_name = @selector(originalMethodName)
      char *method_types = “v@:“ //returns void, params id(self),selector(_cmd)
      IMP method_imp = 0x000FFFF (MyBundle`[MyClass originalMethodName])
 }

Method m2 { 

       SEL method_name = @selector(swizzle_originalMethodName)
       char *method_types = “v@:”
       IMP method_imp = 0x1234AABA (MyBundle`[MyClass swizzle_originalMethodName])
 }

我们方法实现如下,在交换的方法里面调用原来的方法:

   - (void) originalMethodName //m1
     {
     }
     - (void) swizzle_originalMethodName //m2
     {
            [self swizzle_originalMethodName];//call original method
     }

那么这两个方法看起来就是这样的:

Method m1 { 

     SEL method_name = @selector(originalMethodName)
     char *method_types = “v@:“ //returns void, params id(self),selector(_cmd)
     IMP method_imp = 0x1234AABA (MyBundle`[MyClass swizzle_originalMethodName])
 }

Method m2 {

     SEL method_name = @selector(swizzle_originalMethodName)
     char *method_types = “v@:”
     IMP method_imp = 0x000FFFF (MyBundle`[MyClass originalMethodName])
 }

那么问题就来了,因为这样导致_cmd改变了,要是原来的方法根据_cmd做了操作的话(原方法实现一般都是看不到的),这时候就会出事了:

- (void) originalMethodName //m1
 {
          assert([NSStringFromSelector(_cmd) isEqualToString:@“originalMethodNamed”]);
 }

那么我们在看看OBJC_EXPORT IMP method_setImplementation(Method m, IMP imp)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);这个方法来交换方法,该方法调用之后会返回原方法的实现,知道上面的问题之后,我们最好的交换方式就是用一个C语言函数实现去替换原方法实现,C函数大概长这样的:

void __Swizzle_OriginalMethodName(id self, SEL _cmd)
 {
//调用原方法
originalImp(self,_cmd);
//code
 }

那么我们下面的代码可能长这样:

IMP swizzleImp = (IMP)__Swizzle_OriginalMethodName;
IMP originalImp = method_setImplementation(method,swizzleImp);

拿这两个方法来说,主要就是防止人家的代码里面根据selector参数去做了操作而出现问题,这种情况多出现在你的代码用作三方等,要是自己项目的话,还是随便写的,不过说回来,要是苹果的方法里面这样用了,那么我们就不能用OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);交换哦


还是那句话,如您发现任何错误,欢迎留言指正~

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值