#import "ViewController.h"

/*
Runtime(交换方法):主要想修改系统的方法实现 需求: 比如说有一个项目,已经开发了2年,忽然项目负责人添加一个功能,每次UIImage加载图片,告诉我是否加载成功 当系统提供的控件不能满足我们的需求的时候,我们可以 1:通过继承系统控件,重写系统的方法,来扩充子类的行为(super的调用三种情况)
2:当需要为系统类扩充别的属性或是方法的时候,与哪个类有关系,就为哪个类创建分类。3:利用runtime修改系统的类,增加属性,交换方法,消息机制,动态增加方法 解决方法:1:重写系统的方法:新建类继承系统的类,重写系统的方法(要是覆盖父类的行为就不需要调用super,或是在super方法之下调用:在保留父类super原有的行为后,扩充子类自己的行为,代码写在super之上,可以修改super要传递的参数,例如重写setframe,要是想保留父类的行为就不要忘记调用super)。弊端:需要在每个类中都需要引入头文件 2:写分类:为哪个系统的类扩充属性和方法,就为哪个类写分类 3:利用runtime底层的实现来修改或是访问系统的类:增加属性,交换方法,消息机制,动态增加方法 3:本需求利用runtime:不需要导入头文件,调用的还是系统类原来的方法,只是利用了runtime的交换方法。
给系统的imageNamed添加功能,只能使用runtime(交互方法)
1.给系统的方法添加分类
2.自己实现一个带有扩展功能的方法
3.交互方法,只需要交互一次, 1.自定义UIImage
2.UIImage添加分类 */ @interface ViewController () @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; // imageNamed => xmg_imageNamed 交互这两个方法实现
UIImage *image = [UIImage imageNamed:@"1.png"]; } @end
#import "UIImage+Image.h"
#import <objc/message.h> /**
* 总结:
1: + (void)load与+ (void)initialize的区别:+ (void)load:当类加载进内存的时候调用,而且不管有没有子类,都只会调用一次,在main函数之前调用,用途:1:可以新建类在该类中实现一些配置信息 2:runtime交换方法的时候,因为只需要交换一次方法,所有可以在该方法中实现交换方法的代码,用于只实现一次的代码 2:+ (void)initialize:当类被初始化的时候调用,可能会被调用多次,若是没有子类,则只会调用一次,若是有子类的话,该方法会被调用多次,若是子类的继承关系,先会调用父类的+ (void)initialize方法,然后再去调用子类的+ (void)initialize方法(若是继承关系,调用某个方法的时候,先会去父类中查找,若是父类中没有方法的实现就去子类中查找) 用途:1:在设置导航栏的全局背景的时候,只需要设置一次,可以重写该方法设置,最好是在该方法判断子类,若是自己,则实现设置全局导航栏的方法,若不是自己则跳过实现。2:在创建数据库代码的时候,可以在该方法中去创建,保证只初始化一次数据库实例,也可以用dispatch或是懒加载的方法中初始化数据库实例,也能保证只初始化一次数据库实例。其中也可以在+ (void)initialize方法中用dispatch也能保证即使有子类也只会初始化一次 2:交换方法:1:获取某个类的方法:class_getClassMethod:第一个参数:获取哪个类的方法 第二个参数:SEL:获取哪个方法 Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:)); // 交互方法:runtime
method_exchangeImplementations(imageNamedMethod, xmg_imageNamedMethod); 也就是外部调用xmg_imageNamed就相当于调用了imageNamed,调用imageNamed就相当于调用了xmg_imageNamed 3:在分类中,最好不要重写系统方法,一旦重写,把系统方法实现给干掉,因为分类不是继承父类,而是继承NSObject,super没有改类的方法,所以就直接覆盖掉了父类的行为 */
@implementation UIImage (Image)
// 把类加载进内存的时候调用,只会调用一次
+ (void)load
{
// self -> UIImage
// 获取imageNamed
// 获取哪个类的方法
// SEL:获取哪个方法
Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));
// 获取xmg_imageNamed
Method xmg_imageNamedMethod = class_getClassMethod(self, @selector(xmg_imageNamed:)); // 交互方法:runtime
method_exchangeImplementations(imageNamedMethod, xmg_imageNamedMethod);
// 调用imageNamed => xmg_imageNamedMethod
// 调用xmg_imageNamedMethod => imageNamed
} // 会调用多次
//+ (void)initialize
//{
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
//
// });
//
//} // 在分类中,最好不要重写系统方法,一旦重写,把系统方法实现给干掉 //+ (UIImage *)imageNamed:(NSString *)name
//{
// // super -> 父类NSObject
//
//} // 1.加载图片
// 2.判断是否加载成功
+ (UIImage *)xmg_imageNamed:(NSString *)name
{
// 图片
UIImage *image = [UIImage xmg_imageNamed:name]; if (image) {
NSLog(@"加载成功");
} else {
NSLog(@"加载失败");
} return image;
} @end

runtime 的实现原理:

二:通过继承重写实现:每次都需要导入头文件,而且项目中很多地方都得需要修改

#import <UIKit/UIKit.h>

@interface XMGImage : UIImage

@end
#import "XMGImage.h"

@implementation XMGImage

// 重写方法:想给系统的方法添加额外功能
+ (UIImage *)imageNamed:(NSString *)name
{
// 真正加载图片:调用super初始化一张图片
UIImage *image = [super imageNamed:name]; if (image) {
NSLog(@"加载成功");
} else {
NSLog(@"加载失败");
} return image; } @end

* 开发使用场景:系统自带的方法功能不够,给系统自带的方法扩展一些功能,并且保持原有的功能。

* 方式一:继承系统的类,重写方法.

* 方式二:使用runtime,交换方法.

```

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

// 需求:给imageNamed方法提供功能,每次加载图片就判断下图片是否加载成功。

// 步骤一:先搞个分类,定义一个能加载图片并且能打印的方法+ (instancetype)imageWithName:(NSString *)name;

// 步骤二:交换imageNamed和imageWithName的实现,就能调用imageWithName,间接调用imageWithName的实现。

UIImage *image = [UIImage imageNamed:@"123"];

}

@end

@implementation UIImage (Image)

// 加载分类到内存的时候调用

+ (void)load

{

// 交换方法

// 获取imageWithName方法地址

Method imageWithName = class_getClassMethod(self, @selector(imageWithName:));

// 获取imageWithName方法地址

Method imageName = class_getClassMethod(self, @selector(imageNamed:));

// 交换方法地址,相当于交换实现方式

method_exchangeImplementations(imageWithName, imageName);

}

// 不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super.

// 既能加载图片又能打印

+ (instancetype)imageWithName:(NSString *)name

{

// 这里调用imageWithName,相当于调用imageName

UIImage *image = [self imageWithName:name];

if (image == nil) {

NSLog(@"加载空的图片");

}

return image;

}

@end

```

ios开发runtime学习二:runtime交换方法的更多相关文章

  1. ios开发网络学习二:URL转码以及字典转模型框架MJExtension的使用

    一:url转码,当url中涉及到中文的时候,要考虑转码,用UTF8对中文的url进行转码 #import "ViewController.h" @interface ViewCon ...

  2. iOS开发RunnLoop学习二:GCD中的定时器

    #import "ViewController.h" @interface ViewController () /** 注释 */ @property (nonatomic, st ...

  3. iOS开发-定制多样式二维码

    iOS开发-定制多样式二维码   二维码/条形码是按照某种特定的几何图形按一定规律在平台(一维/二维方向上)分布的黑白相间的图形纪录符号信息.使用若干个与二进制对应的几何形体来表示文字数值信息. 最常 ...

  4. iOS开发Swift篇—(十)方法

    iOS开发Swift篇—(十)方法 一.简单说明 跟其他面向对象语言一样,Swift中的方法可以分为2大类: (1)实例方法(Instance Methods) 在OC中,实例方法以减号(-)开头 ( ...

  5. IOS开发-文件管理(二)

    IOS开发-文件管理(二) 五.Plist文件 String方式添加               NSString *path = [NSHomeDirectory( )  stringByAppen ...

  6. iOS开发如何学习前端(2)

    iOS开发如何学习前端(2) 上一篇成果如下. 实现的效果如下. 实现了一个横放的<ul>,也既iOS中的UITableView. 实现了当鼠标移动到列表中的某一个<li>,也 ...

  7. 关于iOS开发的学习

    关于iOS开发的学习,打个比方就像把汽车分解:    最底层的原料有塑料,钢铁    再用这些底层的东西造出来发动机,座椅    最后再加上写螺丝,胶水等,把汽车就拼起来了 iOS基本都是英文的资料, ...

  8. iOS开发中几个重要的方法

    iOS开发中几个重要的方法: 加载类到内存,程序刚启动的时候调用,调用在main函数之前 1.+(void)load{ } 初始化类,类第一次使用的时候调用一次 2.+(void)initialize ...

  9. IOS开发-几种截屏方法

    IOS开发-几种截屏方法 1.        UIGraphicsBeginImageContextWithOptions(pageView.page.bounds.size, YES, zoomSc ...

  10. iOS开发如何学习前端(1)

    iOS开发如何学习前端(1) 我为何学前端?因为无聊. 概念 前端大概三大块. HTML CSS JavaScript 基本上每个概念在iOS中都有对应的.HTML请想象成只能拉Autolayout或 ...

随机推荐

  1. 妙味css3课程---1-2、css3中新增的伪类和伪元素有哪些

    妙味css3课程---1-2.css3中新增的伪类和伪元素有哪些 一.总结 一句话总结: 1.div:target{}是什么意思? 比如a标签的锚点链接到div,div:target{}就可以找到这个 ...

  2. Flume的Storage&Master

    storage是存储系统,可以是一个普通file,也可以是HDFS,HIVE,HBase,分布式存储等. Master是管理协调Agent和Collector的配置等信息,是flume集群的控制器.

  3. 2.3 Streams API 官网剖析(博主推荐)

    不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ 2.3 Streams API 2.3 Streams API 在0..0增加了一个 ...

  4. bind()和trigger()额外数据

    $(function(){ $('input').click(function(e,data1,data2,data3,data4){ alert(data1 + '|' + data2 + '|' ...

  5. c#的中英文混合字符串截取 public static string SubString(string inputString, int byteLength)

    /// <summary>        /// c#的中英文混合字符串截取(区分中英文)        /// </summary>        /// <param ...

  6. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

  7. 【例题 8-5 UVA - 11054】Wine trading in Gergovia

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 考虑第一个店. 如果它要酒的话,只能从第二个店那里运过来. 这样,问题就转化成后n-1个店的问题了. 然后会发现,第二家店它的情况也 ...

  8. asp.net Code学习二(使用vs 2015 update 3)

    1.在vs 2015上搭建asp.net core:  安装 .Net core sdk.vs2015 tool 即可使用vs 2015开发asp.net core. 2.Net core中国学习小组 ...

  9. linux下多进程的文件拷贝与进程相关的一些基础知识

    之前实现了用文件IO的方式能够实现文件的拷贝,那么对于进程而言,我们是否也能够实现呢? 答案是肯定的. 进程资源: 首先我们先回想一下,进程的执行须要哪些资源呢?其资源包含CPU资源,内存资源,当然还 ...

  10. ubuntu-安装中文拼音输入法

    一下内容转载自http://blog.chinaunix.net/uid-24410388-id-3501873.html 自己验证了可用.转载了,已留做日后使用 步骤: step1:安装ibus所需 ...