动态的交换方法能够给项目中大量已经使用的方法 进行拦截增加操作

实践:利用运行时交换系统的ImageNamed:方法

应用背景

当系统需要适配ios7和ios8时可能会有显示不同图片的需求,但在老项目上开发ios7程序时并未考虑到ios8的适配,当项目上有几百处地方用到ImageNamed:方法时,如果选用最直接的办法,在该方法之前进行判断,如果为ios8就显示另外一张图片,这样的工作量明显会很大,所以可以用运行时的方法来解决。

新建一个项目,准备两张图片,一张图片名为close为ios7而准备,一张close_os8为ios8而准备

在storyboard里添加两个个UIImageView控件

@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); }

如此就利用运行时机制实现了系统方法和自定义方法互相交换实现

需要了解的知识点

一、什么是运行时

运行时是一套纯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)

Runtime 应用(一)拦截系统自带的方法交换实现的更多相关文章

  1. 快速上手Runtime(三)之方法交换

    开发过程中,我们经常会用到系统类,而它提供的方法又不能完全满足我们开发的需要,那么在此时,我们需要为系统自带的方法扩展一些功能,而且还要保证原有的功能可正常使用.假设咱们现在有这么一个需求,我们在调用 ...

  2. iOS开发——运行时OC篇&使用运行时获取系统的属性:使用自己的手势修改系统自带的手势

    使用运行时获取系统的属性:使用自己的手势修改系统自带的手势 有的时候我需要实现一个功能,但是没有想到很好的方法或者想到了方法只是那个方法实现起来太麻烦,一或者确实为了装逼,我们就会想到iOS开发中最牛 ...

  3. Notepad2替代系统自带的记事本

    事情是这样的,平时我经常把一些文字复制到记事本中编辑好了再复制到目标位置,可以在系统自带的记事本中替换删除一些内容,记事本小巧,占用很少的资源,我很喜欢:但今天复制的内容中有很多数字和一些我不想要的内 ...

  4. 如何获取安卓系统自带应用的package和activity

    之前在做appium自动化测试的时候,参考网上的例子,运行安卓系统自带的app,所以,就需要获取系统自带的package(包名)和activity.这里简单记录一下,不一定适合所有的系统应用. 运行环 ...

  5. 重装系统后如何删除系统自带的office2003

    背景:操作系统重装后,系统自带的office2003版本太低不好使用,需要安装更高版本的如2010,但是卸载时提示“无法打开此修补程序包……”,从而无法卸载.经网上查询,采用以下解决办法: 在注册表中 ...

  6. C语言中使用系统自带的快排函数

    题目 . 德才论 () 宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取 ...

  7. HDU 1257 最少拦截系统【LIS】

    题意:类似于套娃娃,问最少需要多少个拦截系统. 思路: 假设已经有m个导弹拦截序列 r1:x11>=x12>=x13>=...>=x1n r1:x21>=x22>= ...

  8. HDU-1257 导弹拦截系统 http://acm.hdu.edu.cn/showproblem.php?pid=1257

    Problem Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高 ...

  9. Ios二维码扫描(系统自带的二维码扫描)

    Ios二维码扫描 这里给大家介绍的时如何使用系统自带的二维码扫描方法和一些简单的动画! 操作步骤: 1).首先你需要搭建UI界面如图:下图我用了俩个imageview和一个label 2).你需要在你 ...

随机推荐

  1. AM335X can驱动移植

    驱动选择 make menuconfig [*] Networking support ---> <*> CAN bus subsystem support ---> --- ...

  2. MyBatis 网络资料

    http://mybatis.github.io/mybatis-3/zh/index.html 官方文档例子 http://blog.csdn.net/rootsuper/article/detai ...

  3. 如何打一手好Log

    如果项目上过线的话,那你一定知道Log是多么重要. 为什么说Log重要呢?因为上线项目不允许你调试,你只能通过Log来分析问题.这时打一手好Log的重要性绝不亚于写一手好代码.项目出问题时,你要能拿出 ...

  4. KafkaStream实现wordcount

    KTable应用 KTable wordCounts = textLines // Split each text line, by whitespace, into words. .flatMapV ...

  5. Linux远程复制文件

    将本机文件app.properties 复制到用户为root,ip为ip的具体路径下去 scp app.properties root@ip:/apps/javaconf/common/ 其他参考: ...

  6. kill 的常用信号

    kill命令用于终止指定的进程(terminate a process),是Unix/Linux下进程管理的常用命令.通常,我们在需要终止某个或某些进程时,先使用ps/pidof/pstree/top ...

  7. Hibernate- QBC-基本查询

    01.环境搭建 02.基本查询 1.方法说明 方法 说明 Restrictions.eq = Restrictions.allEq 利用Map来进行多个等于的限制 Restrictions.gt &g ...

  8. QSignalMapper类处理多信号关联同一个槽的方法(2)

    例1: QSignMapper *mapper = new QSignMapper(this) QPushButton *btn1 = new QPushButton(this); btn1-> ...

  9. 论SparkStreaming的数据可靠性和一致性

    转自: http://www.csdn.net/article/2015-06-21/2825011 摘要:眼下大数据领域最热门的词汇之一便是流计算了,而其中最耀眼的无疑是来自Spark社区的Spar ...

  10. Mastering the game of Go with deep neural networks and tree search浅析

    Silver, David, et al. "Mastering the game of Go with deep neural networks and tree search." ...