iOS 多个category同时交换同一个方法

2021-09-07 16:47:42 浏览数 (1)

1.问题

问题1:同一个类多个category有相同的方法,是如何执行?有没有例外?

文件顺序

结论: 1.结果会覆盖,后面的会覆盖前面的,最后执行的是2的方法。无论是类方法还是实例方法。后面代码会做验证。 2.每个category的 (void)load方法是独立,都会执行,不会相互覆盖。

问题2:同一个类多个category同时交换一个方法,执行顺序如何?(包括交换后方法同名,交换后方法不同名)

结论: 1.如果交换后方法同名,最后只运行类中的方法 2.如果交换后方法不同名,会倒叙执行文件的方法,如上:先执行2->1->宿主类

2.代码

2.1 RuntimeViewController代码

代码语言:javascript复制
#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代码

代码语言:javascript复制
#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代码

代码语言:javascript复制
#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. 假设有1,2,3分别代表:类、category1,category2.
  2. category1中方法交换

第一步交换

  1. 3与2交换,由于第一步2与1交换了,相当于3与1交换,即3指向了1指向的方法

第二步第一次交换

  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方法。

0 人点赞