Object - C运行时应用(一)—— 拦截系统自带的方法交换实现
来源:互联网 发布:高仿椰子 知乎 编辑:程序博客网 时间:2024/05/16 11:48
一、什么是运行时
运行时是一套纯C语言的API,编译器最终都会将OC代码转化为运行时代码。
二、运行时常用函数
1、<objc/runtime.h>
* 获得某个类的类方法 Method class_getClassMethod(Class cls, SEL name)
* 获得某个对象的对象方法 Method class_getInstanceMethod(Class cls, SEL name)
* 交换两个方法的实现 void method_exchangeImplementations(Method m1, Method m2)
* 关联对象(将值value与对象object关联起来) void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
参数key:将来可以通过key取出这个存储的值
参数policy:存储策略(assign、copy、retain)
* 利用参数key将对象中存储的对应值取出 id objc_getAssociatedObject(id object, const void *key)
* 获得某个类的所有成员变量 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)(outCount会返回成员变量的总数)
* 获得成员变量的名字 const char *ivar_getName(Ivar v)
* 获得成员变量的类型 const char *ivar_getTypeEncoding(Ivar v)
* 释放内存 void free(void *) (当C语言函数名中包含了copy、create、retain、new等词语,那么就需要在最后释放资源)
2、<objc/message.h>
* 给某个对象发送某个消息 void objc_msgSend(void)
三、实践:利用运行时交换系统的ImageNamed:方法
1、应用背景
当系统需要适配ios7和ios8时可能会有显示不同图片的需求,但在老项目上开发ios7程序时并未考虑到ios8的适配,当项目上有几百处地方用到ImageNamed:方法时,如果选用最直接的办法,在该方法之前进行判断,如果为ios8就显示另外一张图片,这样的工作量明显会很大,所以可以用运行时的方法来解决。
新建一个项目,准备两张图片,一张图片名为close为ios7而准备,一张close_os8为ios8而准备
在storyboard里添加连个UIImageView控件
viewDidLoad方法里加载图片,此时没有使用运行时
@interface ViewController ()@property (weak, nonatomic) IBOutlet UIImageView *img1;@property (weak, nonatomic) IBOutlet UIImageView *img2;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; self.img1.image = [UIImage imageNamed:@"close"]; self.img2.image = [UIImage imageNamed:@"fire"]; }@end
运行效果如下:
接下来使用运行时的方法交换imageNamed:的实现,先为UiImage添加一个自定义的创建图片的分类,此时需要导入一个运行时框架#import<objc/runtime.h>,代码如下:
/** * 自定义创建图片方法 */+ (instancetype)imageWithName:(NSString *)name{ NSString *imgN = name; double version = [[UIDevice currentDevice].systemVersion doubleValue]; NSLog(@"%f",version); if (version >= 8.0) { imgN = [NSString stringWithFormat:@"%@_os8",name]; NSLog(@"%@",imgN); } // 此时imageWithName:的实现在运行时已经被改为imageNamed:的实现 return [self imageWithName:imgN];}
在load方法里面实现方法的交换,该方法只会被加载一次
/** * 类第一次加载进内存的时候会调用 */+ (void)load{ // 运行时交换两个方法的实现 Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:)); Method m2 = class_getClassMethod([UIImage class], @selector(imageWithName:)); method_exchangeImplementations(m1, m2); }
接下来是运行结果:
如此就利用运行时机制实现了系统方法和自定义方法互相交换实现
0 0
- Object - C运行时应用(一)—— 拦截系统自带的方法交换实现
- Object-C 获得系统自带的字体
- Object - C运行时应用(三)——实现NSCoding的自动归档和自动解档
- Win10系统删除系统自带应用的方法
- 自制OculusVR控制(一)——利用Unity的自带方法实现VR的控制输入
- 利用命令行删除Android系统自带应用的方法
- eclipse 上调试android的自带应用方法 一
- eclipse 上调试android的自带应用方法 一
- iOS运行时的用途一 -- 交换方法
- iOS 拦截系统自带的Pop事件
- 调试系统自带的应用
- Unity3d自带的自动寻路系统(一)
- Win10恢复自带应用的方法
- cell 的自带的系统方法
- 需要重新系统自带的方法
- 调用系统自带浏览器的方法
- Dialog(一)系统自带功能
- Java应用程序运行时监控方法(一)——JVMTI的应用
- Activity的复习以及在Onstart里设置网络连接
- 2015年Ubuntu最新Redmine的安装和配置
- Fibonacci数列
- TCP标志中的URG和PSH位
- hdu 5037 Frog(贪心)
- Object - C运行时应用(一)—— 拦截系统自带的方法交换实现
- openCL错误码
- 各种排序算法的稳定性和时间复杂度小结
- 如何查看你的计算机CPU的位数?32位或者64位?
- webkit渲染过程
- shared_ptr demo
- HDU ACM 1273 漫步森林
- Java NIO详解及实例和源码下载(一)
- UVA - 10626 Buying Coke