1.问题
问题1:同一个类多个category有相同的方法,是如何执行?有没有例外?
结论:
1.结果会覆盖,后面的会覆盖前面的,最后执行的是2的方法。无论是类方法还是实例方法。后面代码会做验证。
2.每个category的+ (void)load方法是独立,都会执行,不会相互覆盖。
问题2:同一个类多个category同时交换一个方法,执行顺序如何?(包括交换后方法同名,交换后方法不同名)
结论:
1.如果交换后方法同名,最后只运行类中的方法
2.如果交换后方法不同名,会倒叙执行文件的方法,如上:先执行2->1->宿主类
2.代码
2.1 RuntimeViewController代码
#import "RuntimeViewController.h"
#import "RuntimeViewController+ExchangeMethod1.h"
#import "RuntimeViewController+ExchangeMethod2.h"
@interface RuntimeViewController ()
@end
@implementation RuntimeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[RuntimeViewController runtimeLog];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"viewWillAppear_原生的");
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
NSLog(@"viewWillDisappear_原生的");
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(@"viewWillDisappear_原生的");
}
+ (void)runtimeLog{
NSLog(@"RuntimeViewController");
}
@end
2.2RuntimeViewController+ExchangeMethod1代码
#import "RuntimeViewController+ExchangeMethod1.h"
@implementation RuntimeViewController (ExchangeMethod1)
+ (void)load{
NSLog(@"RuntimeViewController load1");
[self exchangeInstanceMethod1:@selector(viewWillAppear:) method2:@selector(wp_viewWillAppear:)];
[self exchangeInstanceMethod1:@selector(viewWillDisappear:) method2:@selector(wp_viewWillDisappear1:)];
}
+ (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2
{
method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2));
}
- (void)wp_viewWillAppear:(BOOL)animated{
NSLog(@"viewWillAppear_ExchangeMethod1");
[self wp_viewWillAppear:animated];
}
- (void)wp_viewWillDisappear1:(BOOL)animated{
NSLog(@"viewWillDisappear_ExchangeMethod1");
[self wp_viewWillDisappear1:animated];
}
//直接覆盖
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(@"viewDidAppear_ExchangeMethod1");
}
+ (void)runtimeLog{
NSLog(@"RuntimeViewController1");
}
@end
2.3RuntimeViewController+ExchangeMethod2代码
#import "RuntimeViewController+ExchangeMethod2.h"
@implementation RuntimeViewController (ExchangeMethod2)
+ (void)load{
NSLog(@"RuntimeViewController load2");
[self exchangeInstanceMethod1:@selector(viewWillAppear:) method2:@selector(wp_viewWillAppear:)];
[self exchangeInstanceMethod1:@selector(viewWillDisappear:) method2:@selector(wp_viewWillDisappear2:)];
}
+ (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2
{
method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2));
}
- (void)wp_viewWillAppear:(BOOL)animated{
NSLog(@"viewWillAppear_ExchangeMethod2");
[self wp_viewWillAppear:animated];
}
- (void)wp_viewWillDisappear2:(BOOL)animated{
NSLog(@"viewWillDisappear_ExchangeMethod2");
[self wp_viewWillDisappear2:animated];
}
//直接覆盖
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(@"viewDidAppear_ExchangeMethod2");
}
+ (void)runtimeLog{
NSLog(@"RuntimeViewController2");
}
@end
3.结果
3.1 runtimeLog与viewDidAppear测试类方法与实例方法会相互覆盖
控制台日志:
RuntimeViewController2
viewDidAppear_ExchangeMethod2
此日志说明category的方法会覆盖宿主类的方法,而多个category类方法与实例方法都会相互覆盖,后面的文件覆盖前面的文件。
3.2 load中的NSLog测试load方法都会执行,方法交换都会生效
控制台日志:
RuntimeViewController load1
RuntimeViewController load2
此日志说明load不会相互覆盖
3.3 viewWillAppear验证交换后方法同名结果
控制台日志:
viewWillAppear_原生的
此日志说明:多个category同时交换同一个方法,且交换后的方法名称也相同,结果等同于没有交换。
原因很简单:ExchangeMethod1交换后,ExchangeMethod2又交换回去了,相当于没有交换。如果新建ExchangeMethod3,你会发现还是有交换的。
3.4 viewWillDisappear验证交换后方法不同名结果
控制台日志:
viewWillDisappear_ExchangeMethod2
viewWillDisappear_ExchangeMethod1
viewWillDisappear_原生的
此日志说明:多个category同时交换同一个方法,交换后的方法名称不相同。如果交换后方法不同名,会倒叙执行文件的方法,如上:先执行2->1->宿主类
3.5 验证3.4交换后的关系
假设有1,2,3分别代表:类、category1,category2.
-
category1中方法交换
-
3与2交换,由于第一步2与1交换了,相当于3与1交换,即3指向了1指向的方法
-
3与2交换,相当于是与1交换,即1指向了3
执行的顺序:3->2->1
1.首先调用的是类(1)中的方法,相当于调用了3
2.3调了本身方法,即调用了2方法
3.2再调了本身方法,即调了1方法
4.最后打印1中的日志
理解了1,2,3的顺序,对号入座即可。
由此验证了 3.4 的打印结果。
总结:
为什么要研究这个问题呢?在使用MJRefresh与FDTemplateLayoutCell框架时,发现同时交换了reloadData方法。