返回
循环 Hook 的坑:揭秘 Method Swizzle 的潜在问题
IOS
2023-11-11 04:24:21
实战 Method Swizzle 的循环 Hook 问题
在这个数据为王的时代,市面上有用户访问的 App 都会进行日志打点。如果一个个页面去打点,实在费时费力。我们不免想通过 AOP 方式去 Hook 我们想要的方法,就能做到一次打点,统一管理的目的。
比如对于一个页面的进出,只需要对 viewWillAppear 和 viewDidDisappear 这两个方法进行 Hook,就能统一打点进入和离开页面的日志。
而对于 Method Swizzle 这种动态替换方法实现的技术,是 AOP 的一种实现方式。它通过替换方法的实现,达到我们修改方法行为的目的。
但是,Method Swizzle 在使用过程中,也存在着一些潜在的问题,需要我们注意。其中,循环 Hook 就是一个典型的问题。
什么是循环 Hook
循环 Hook 顾名思义,就是在一个方法中,不断地调用自身,从而形成一个无限循环。
在 Method Swizzle 中,如果我们对一个方法进行 Hook,并且在这个 Hook 方法中又调用了这个方法,就会形成循环 Hook。
循环 Hook 的危害
循环 Hook 会导致以下问题:
- 内存泄漏: 不断地调用自身,会不断地创建新的对象,从而导致内存泄漏。
- 栈溢出: 不断地调用自身,会不断地压栈,从而导致栈溢出。
- 死锁: 如果两个方法互相 Hook,并都在 Hook 方法中调用对方,就会形成死锁。
如何避免循环 Hook
为了避免循环 Hook,我们可以采用以下措施:
- 使用断点调试: 在 Xcode 中,可以在被 Hook 的方法中设置断点,当断点被触发多次时,说明出现了循环 Hook。
- 使用工具检测: 可以使用一些工具,如 Instruments,来检测循环 Hook。
- 合理设计 Hook 方法: 在 Hook 方法中,不要调用被 Hook 的方法。如果需要调用被 Hook 的方法,可以使用不同的名称或使用间接调用。
示例代码
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// 循环 Hook
[self viewWillAppear:animated];
}
修复方法
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// 修复循环 Hook
if (![self isMemberOfClass:[self class]]) {
[self viewWillAppear:animated];
}
}
总结
Method Swizzle 是 AOP 的一种实现方式,在使用过程中,需要注意循环 Hook 问题。通过合理的设计 Hook 方法,并使用断点调试或工具检测,可以有效避免循环 Hook 的发生。