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:交换方法:
- 给系统的方法添加一个分类
- 自己实现一个带有拓展功能的方法
- 交换方法,只需要交换一次:+(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
欢迎你们的阅读和赞赏、谢谢!