先看第一个问题:分类的加载顺序
举例UIViewController
3个分类分别为UIViewController+A
UIViewController+B
UIViewController+C
.A
1 | + (void)load { |
.B
1 | + (void)load { |
.C
1 | + (void)load { |
运行结果
1 | 2018-03-23 11:06:10.975429+0800 ExchangeImp[4802:195579] ----C--- |
这个顺序是怎么来的的呢,就不卖关子了,本文的重点是第二个问题
其实是这里的顺序,其实压栈的顺序,上面的顺序是C,B,A
我们修改下让以B,A,C输出
运行输出
1 | 2018-03-23 11:09:23.697753+0800 ExchangeImp[4881:201198] ----B--- |
第二个问题:多次使用method_exchangeImplementations同一个方法会是怎样的结果
method_exchangeImplementations
关于该方法的使用请自行学习,不是本文的重点
这里我们同时对系统的presentViewController:animated:completion:
举例
代码结构
1 | . |
A.m
1 | // |
B.m
1 | // |
C.m
1 | // |
ViewController.m
1 | // |
在build-Phase
中的compile source
中顺序如下
运行点击后
1 | 2018-03-23 11:25:04.816560+0800 ExchangeImp[5364:228651] ---B-被加载了-- |
发现2个现象:
- 所有的分类方法都被执行了;
- 正好和加载的顺序相反
下面具体解释下这2个现象
在分类A、B、C执行之前2个方法是这样的指向的
在经历分类B
以后,变成下面这样
所以在如果没有A
和C
的话,那么在执行
1 | - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { |
调用顺序为:presentViewController:animated:completion:
-> NSLog(@"---B-被执行了--");
-> bAlertPresentViewController:animated:completion:)
所以输出顺序应该是
1 | ---B-被执行了-- |
然后弹出vc
回到正题,那么在执行分类A
之前的样子,A方法和presentViewController:animated:completion:
指向就是下图
在执行分类A以后,指向如下
所以如果没有分类C
的话这时候的输出应该为
1 | ---A-被执行了-- |
继续分析,在分类c
执行之前,各个指向为下图
执行以后如下
则执行顺序就很清楚了,到这里也就解释了为何一开始是的输出
1 | 2018-03-23 11:25:04.816560+0800 ExchangeImp[5364:228651] ---B-被加载了-- |
接下来通过logo打印证实上面的观点
改造下之前的代码以B.m
为例
1 | // |
执行以后
1 | ExchangeImp[6709:319693] ---B-被加载了-- |
主要看下originalMethod
的地址
A的开始bengin的开始也即是originalMethod
指向为0x10b6241d0
,正是在B
B-after中交换后的0x10b6241d0
可以看到每次交换的开始都是上次交换的结果
结论
多次对某个方法进行method_exchangeImplementations
所有交换的都会执行到,执行顺序可以自己在build-phase
中修改
项目地址
(完)