iOS中多方swizzle一个target类的方法执行结果验证
背景:项目越来庞大,业务团队很多的情况下,就会出现一种情况,基础组件被很多业务方所依赖,比如其中的某个方法,被不同的业务方去多次swizzle, 多处hook一个方法,*后执行的方法是哪个?是*后一个hook的使用方还是?
示例代码说明, 4个viewController, 按照以下顺序依次push:
ViewController -> DDMNOtificationViewController -> DDMSwizzledViewController ->
DDMSwizzleSecondViewController
在每个vc的viewDidLoad方法里,调用被hook的方法(此时每个vc的实例方法已经在+load hook了,关于+load的问题后续会写一篇)
@implementation ViewController
– (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSStringFromClass([self class]);
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 44)];
button.backgroundColor = [UIColor yellowColor];
[button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
– (void)ddm_viewcontroller_testInstanceMethod
{
NSLog(@”1:—-%s——“,__func__);
}
– (void)buttonAction
{
DDMNOtificationViewController *notificationVC = [[DDMNOtificationViewController alloc] init];
[self.navigationController pushViewController:notificationVC animated:YES];
}
@end
@implementation DDMNOtificationViewController
+ (void)load
{
[DDMSwizzleClass ddm_swizzle:NSClassFromString(@”ViewController”) originSelector:@selector(ddm_viewcontroller_testInstanceMethod) swizzleClass:[DDMNOtificationViewController class] swizzleSelector:@selector(ddm_notification_InstanceMethod)];
}
– (void)ddm_notification_InstanceMethod
{
NSLog(@”2:—-%s——“,__func__);
}
– (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = NSStringFromClass([self class ]);
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 44)];
button.backgroundColor = [UIColor redColor];
[button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
[self ddm_notification_InstanceMethod];
}
– (void)buttonAction
{
DDMSwizzledViewController *notificationVC = [[DDMSwizzledViewController alloc] init];
[self.navigationController pushViewController:notificationVC animated:YES];
}
@end
@implementation DDMSwizzledViewController
+ (void)load
{
[DDMSwizzleClass ddm_swizzle:[ViewController class] originSelector:@selector(ddm_viewcontroller_testInstanceMethod) swizzleClass:[DDMSwizzledViewController class] swizzleSelector:@selector(ddm_swizzled_InstanceMethod)];
}
– (void)ddm_swizzled_InstanceMethod
{
NSLog(@”3:—-%s——“, __func__);
}
– (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.title = NSStringFromClass([self class ]);
[self ddm_swizzled_InstanceMethod];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 44)];
button.backgroundColor = [UIColor blueColor];
[button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
– (void)buttonAction
{
DDMSwizzleSecondViewController *notificationVC = [[DDMSwizzleSecondViewController alloc] init];
[self.navigationController pushViewController:notificationVC animated:YES];
}
@end
@implementation DDMSwizzleSecondViewController
+ (void)load
{
[DDMSwizzleClass ddm_swizzle:[ViewController class] originSelector:@selector(ddm_viewcontroller_testInstanceMethod) swizzleClass:[self class] swizzleSelector:@selector(ddm_secondswizzled_InstanceMethod)];
}
– (void)ddm_secondswizzled_InstanceMethod
{
NSLog(@”4:—-%s——“, __func__);
}
– (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.title = NSStringFromClass([self class]);
[self ddm_secondswizzled_InstanceMethod];
}
@end
打印结果:
DDMDemo[x:x] 1:[ViewController ddm_viewcontroller_testInstanceMethod]——
DDMDemo[x:x] 2:[DDMNOtificationViewController ddm_notification_InstanceMethod]——
DDMDemo[x:x] 3:[DDMSwizzledViewController ddm_swizzled_InstanceMethod]——
结果很显然:在DDMNOtificationViewController中执行的是ViewController的方法,DDMSwizzledViewController中执行的是DDMNOtificationViewController,依次类推。。
这也符合常理,各个使用方hook的方法肯定都得走到。
这里有人可能会有疑问,上述打印结果这个和这几个VC的+load方法执行顺序有关吧, ViewController -> DDMNOtificationViewController -> DDMSwizzledViewController -> DDMSwizzleSecondViewController ,
确实如上图,可以尝试调整source file的编译顺序会对打印结果产生影响。
结论是,使用方hook其他公用的方法,会调用到在这个类+load执行前的其他类的hook方法内容。