[Runtime]-交换方法

1:比如我们有个需求:让UIImage加载图片的时候,告诉我们是否加载成功了

前言:

/**
 Runtime(交换方法):只要是想修改系统的方法实现
 
 *  1: 需求:让UIImage加载图片,告诉我是否加载成功、给系统UIImageName添加功能,只能使用Runtime
 *  2: //解决办法一:自定义UIImage方法、重写:可以解决
 *  弊端:1:每次使用,都需要导入
         2:如果项目开发很久了,现在这样一个一个改很麻烦
 
 *  3: //解决办法二:只能给UIImage添加分类,使用Runtime
         1:给系统的方法添加一个分类
         2:自己实现一个带有拓展功能的方法
         3:交换方法,只需要交换一次
 */

> 01-我们想到的方法可能就是自定义UIImage类,拓展这个方法:如

  • 
    #import <UIKit/UIKit.h>
    
    @interface XJUIImage : UIImage
    
    + (UIImage *)imageNamed:(NSString *)name ;
    
    @end
    
    
    
    #import "XJUIImage.h"
    
    @implementation XJUIImage
    + (UIImage *)imageNamed:(NSString *)name {
        UIImage *image = [super imageNamed:name];
        if (image) {
            NSLog(@"加载成功");
        }else {
            NSLog(@"加载失败");
        }
        
        return image;
    }
    @end
    

然后调用的时候:先导入头文件

  • #import "XJUIImage.h"

最后使用:

  • - (void)viewDidLoad {
        [super viewDidLoad];
        UIImage *image = [XJUIImage imageNamed:@"1.png"];
        //UIImage *image = [UIImage xj_imageNamed:@"2.png"];
        //UIImage *image = [UIImage imageNamed:@"3"];
    }
    

最后就会打印 加载成功 || 加载失败

注意:上面这种思路,可以解决了问题,但是它有一些弊端

                                > 01-每次使用,都需要导入头文件

> 02-如果项目已经开发很久了,你不可能全局的一个一个的这样修改,直接搞死你


> 02-我们可能想要创建一个UIImage分类:但是你如果不使用runtime的话,你还是需要每次导入头文件,还是需要修改方法名

  • // 在分类中,最好不要重写系统的办法,一般重写了,就把系统方法给覆盖了
    //+ (UIImage *)imageNamed:(NSString *)name {
    //    //super:指向父类,所以在分类不能调用super
    //}
    
  • #import "UIImage+XJImage.h"
  • UIImage *image = [UIImage xj_imageNamed:@"2.png"];

注意:它的弊端和上面是一样的问题,不能很好的帮助我们解决问题。


> 03-使用runtime:交换方法:

  1. 给系统的方法添加一个分类
  2. 自己实现一个带有拓展功能的方法
  3. 交换方法,只需要交换一次:+(void)load;
  • #import <UIKit/UIKit.h>
    
    @interface UIImage (XJImage)
    + (UIImage *)xj_imageNamed:(NSString *)name;
    @end
    
    
    
    #import "UIImage+XJImage.h"
    #import <objc/message.h>
    
    @implementation UIImage (XJImage)
    
    // 在分类中,最好不要重写系统的办法,一般重写了,就把系统方法给覆盖了
    //+ (UIImage *)imageNamed:(NSString *)name {
    //    //super:指向父类,所以在分类不能调用super
    //}
    
    
    // 把类加载进内存的时候调用,只会调用一次
    + (void)load {
        // 交换方法:runtime
        
        // 获取imageNamed
        Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
        
        // 获取xj_imageNamed
        Method xj_imageNameMethod = class_getClassMethod(self, @selector(xj_imageNamed:));
        
        method_exchangeImplementations(imageNameMethod, xj_imageNameMethod);
    }
    
    
    // 还有一种方式:但是会调用多次,我们可以结合dispatch_once_t:保证只会执行一次,swift中只能使用这个方法,因为swift中没有load方法
    + (void)initialize {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            
        });
    }
    
    
    // 以后想修改系统的方法,但是又不想重名字,可以在前面添加前缀
    + (UIImage *)xj_imageNamed:(NSString *)name {
        UIImage *image = [UIImage xj_imageNamed:name];
        
        if (image) {
            NSLog(@"xj--加载成功了");
        }else {
            NSLog(@"xj--加载失败了");
        }
        
        return image;
    }
    @end

注意:它的好处:

  • 不需要导入任何头文件
  • 不需要修改系统原来的调用方法,因为我们使用runtime以后,它调用系统方法就会自动去交换变成调用我们的方法

 

意见反馈邮件:1415429879@qq.com
欢迎你们的阅读和赞赏、谢谢!

 

转载于:https://my.oschina.net/shengbingli/blog/726559

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值