1.声明:
学习底层的过程不止是装逼,更多的是学以致用,举一反三。
本文观点均为个人观点,不对之处,欢迎指教。
一:什么是方法交换。

1.图中我们假设这是ViewController类的数据结构图,中分别解释下图中的A,B,C.
A:就是ViewController类。
B: 里面藏着ViewController分类的方法列表。
C:ViewController宿主类(不是分类)的方法列表。
图中我们知道,分类的方法列表和宿主类的方法列表存储的位置是不一样的。
2.就methodList内部是什么,我们分析下。


我们说函数的四要素,如图所示。这四个东西唯一决定了一个函数。
现在原理明白了,那么我们运行时交换函数的方法名称,那么其余不变。就实现了方法交换。
3.综上,我们给方法交换下个定义。
3.1 在
同一类(红色,同一类,后面阐述)中,我们通过运行时,通过两个方法选择器(@selector())找到对应的method,最后对method进行交换的过程。
二:我们就实际探讨下methedSwizzling在项目开发中的实际用处。
用处:若您第一次听说,肯定觉得,有毛病吧,我写个方法,实现功能,为啥要替换?
下面我提几个场景:
1.许多app会有皮肤设置,我们对UIView的
setBackgroundColor方法交换,通过不同的皮肤设置不同的背景色。
2.在AFNetworking中也有应用,AFN中利用runtime将访问网络的方法做了替换,替换后可以监听网络连接状态
3.统计,特殊场合,自己想想。。 看来方法交换用处挺多。
三:我们要怎么进行方法交换才是最好的。
相信你肯定听过Load方法
1.说下load方法的特性;
load方法是main函数执行之前就调用了。
如果在类与分类中都实现了 load 方法,它们都会被调用,不像其它的在分类中实现的方法会被覆盖,这就使 load 方法成为了方法调剂的绝佳时机。
四:那就举个例子吧;

我们对ViewDidLoad方法替换成swiz_ViewDidLoad,此时打印的是swiz_ViewDidLoad方法,view的背景色是红色。
五:开发中我们都用过数组,字典的安全方法,也就是防止判断nil对象的插入,数组的越界引起的奔溃。
1.于是项目中分类是这么写的。

2.使用的时候,你是这么用的

3.相信这样的代码比比皆是对吧。
思考:如果我们把
cd_safeObjectAtIndex和系统的ObjectAtIndex方法替换,那么我们表面上用的还是ObjectAtIndex,其实内部实际实行的是cd_safeObjectAtIndex的安全方法。
多么美好的想法。
我们把addObject, objectAtIndex,insertObject:atIndex:,removeObjectAtIndex:全部替换。
再也不用担心数组,字典的越界等问题了。
六:说到我们就开始行动,对数组的分类方法,进行交换
1.我们创建数组的safe分类,在load方法中进行方法交换

解释一下:
A: 这里我们分别对NSArray类的ObjectAtindex:和safeObjectAtIndex:方法进行了交换。
B:如果有值,调用safeObjectAtIndex:
此时你可能会怀疑,额这里不是进行了循环调用了吗?
回答是:不会的,此时你调用safeObjectAtIndex:实际是调用ObjectAtindex:方法了

好:我们创建了一个空数组,然后打印数组的第二个元素。毫无疑问,这里会数组越界引起奔溃。
但是由于我们,进行了方法交换,理论上,这里是不会奔溃的。
那就运行一下吧。

mmp,奔溃了。
插曲:先想一想,按照上面的逻辑,这里是不应该奔溃的
查看奔溃日志
** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 2 beyond bounds for empty NSArray’
奔溃我明明创建的是
NSArray的初始化方法,怎么奔溃打印的是
__NSArray0这个类呢。
2.这个问题我们先放下:对数组的分类,方法交换是
NSArray修改
__NSArray0类型

此时我们在看打印结果

额:效果实现了,数组明明是越界了,但是我们替换了安全的方法,返回了空,越界也不可怕了。
wow大功告成,原来这么简单啊。
希望你继续看下去??
2.那我们就多试试,看看是不是万无一失;
我们换下数组arr的初始化方法

此时还会数组越界吗?运行一下试试。

mmp,又奔溃。说现在创建的数组是 __NSSingleObjectArrayI类型。。
我必须改成不奔溃,暴脾气

运行,

如我们想象的一样,不崩溃了,确实打印了数组越界,但是走了安全的方法,大功告成
七:通过六的例子,我们不得不陷入深深的思考。为什么会这样。
1.查看资料,我们引入一个概念,叫做
类簇
类簇:先不解释,说下大家都熟悉的
工厂设计模式
工厂设计模式:比如福特汽车工厂:
他能生产福克斯,蒙迪欧,锐界,翼虎,野马类型的轿车
NSArray工厂,能生产__NSSingleObjectArrayI,__NSArray0的类型的数组
多么清新脱俗的比喻,简单粗暴,易于理解。
类簇
在iOS的Foundation框架中,类簇是一种常用的设计模式,他将一些相近的,私有的,具体的子类组合在一个实体的抽象类下面,我称这个抽象类为实体的,是因为和我们交互的接口承载者,就是这个抽象大类。我们平时常用的三大类,NSString,NSArray,NSDictionary都是类簇,我们通过他们创建的对象都是其子类对象的实例化,并不是他本身的实例化。
就等于,我从福特公司买了一辆轿车,是福特产的,但是具体买的却是蒙迪欧。
关于类簇的理解,工厂设计模式,你可以看这篇文章。
现在我们看下之前我给方法交换的定义:
在
同一类(红色,同一类,后面阐述)中,我们通过运行时,通过两个方法选择器(@selector())找到对应的method,最后对method进行交换的过程。
我特别强调了同一类:那以后我们开发中,如果我们方法交换的前后类都是同一个类,那么可以放心使用。
那如果是NSString,NSArray,NSDictionary等抽象类,
打死不能方法交换, 打死不能方法交换, 打死不能方法交换
不然真会出现一些你排查不到的问题,慎用慎用。
七:我们看下一个封装很好的例子,就是对NSString,NSArray,NSDictionary安全方法替换的博客。
这是我从网上看到对数组安全方法的方法交换封装的github
初次看到,感觉我一直想搞的事情,终于有前人已经封装好了。

内部实现也就是:对于不同初始化的NSArray的方法,类名都进行了一一修改,可以说是很用心,用的话,也大致都满足开发需求了。
但是我没看到
__NSArray0类型的相关转化,所以当我用NSArray *arr = @[@“1"];初始化时,
项目就奔溃了。
八:关于methodSwizzling的思考:
一开始:我说用于统计,这场景没遇到过,但是确实是一个极佳的例子,这里记录下。
当你对一个知识点,进行了深入的理解之后。那么如何使用,如何闭坑。也就玩的游刃有余了。
使用 Method Swizzling 编程就好比切菜时使用锋利的刀,一些人因为担心切到自己所以害怕锋利的刀具,可是事实上,使用钝刀往往更容易出事,而利刀更为安全。
勉励:如果我想学习一个东西,请坚持一下几点
1.这东西是什么?
2.这东西怎么用?在哪里用最好?
3.这东西开发中的实际用处?
4.这东西有什么坑,要注意什么?
5.举一反三。
如果你喜欢这篇文章,或者有任何疑问,可以扫描第一个二维码,加楼主好友哦
也可以扫第二个二维码,关注楼主个人微信公众号。这里有很多生活,职业,技术相关的文章哦。欢迎您的到来。
微信号: 公众号