也是在看过开源代码MLeaksFinder受到的启发,写一个很简单的检测内存泄露的工具,我们知道向一个已经被销毁的对象发送消息是不会崩溃的,假如一个VC存在内存泄露,那么它就不会被释放掉,我们可以想向它发送消息,如果它收到了消息,那么这个VC的代码就一定存在问题.
代码实现思路:可以在VC中设置一个属性,viewWillAppear的时候设置为NO,pop返回出栈的时候(暂时只考虑pop情况)设置为YES,我们在viewDidDisappear中,延迟访问这个这个属性,如果他为YES,那么就代表存在内存问题.
新建一个VC的Category:UIViewController+LeaksTest
hook:viewWillAppear,设置自定义属性的值为NO;viewDidDisappear中延迟访问属性
const char * WPVCPOPFLAG;
@implementation UIViewController (LeaksTest)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self wp_swizzleOriginSEL:@selector(viewWillAppear:) currentSEL:@selector(wp_viewWillAppear:)];
[self wp_swizzleOriginSEL:@selector(viewDidDisappear:) currentSEL:@selector(wp_viewDidDisappear:)];
});
}
+ (void)wp_swizzleOriginSEL:(SEL)originSEL currentSEL:(SEL)currentSEL{
Method originMethod = class_getInstanceMethod([self class], originSEL);
Method currentMethod = class_getInstanceMethod([self class], currentSEL);
method_exchangeImplementations(originMethod, currentMethod);
}
-(void)wp_viewWillAppear:(BOOL)animated
{
[self wp_viewWillAppear:animated];
objc_setAssociatedObject(self, WPVCPOPFLAG, @(NO), OBJC_ASSOCIATION_RETAIN);
}
-(void)wp_viewDidDisappear:(BOOL)animated
{
[self wp_viewWillAppear:animated];
if ([objc_getAssociatedObject(self, WPVCPOPFLAG) boolValue]) {
//发送消息
[self willDelloc];
}
}
- (void)willDelloc{
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf isNotDelloc];
});
}
- (void)isNotDelloc{
NSLog(@"%@ IS NOT DELLOC",NSStringFromClass([self class]));
}
在这个VC出栈的时候,设置自定义属性的值,创建UINavigationController+LeakTest
@implementation UINavigationController (LeakTest)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self wp_swizzleOriginSEL:@selector(popViewControllerAnimated:) currentSEL:@selector(wp_popViewControllerAnimated:)];
});
}
+ (void)wp_swizzleOriginSEL:(SEL)originSEL currentSEL:(SEL)currentSEL{
Method originMethod = class_getInstanceMethod([self class], originSEL);
Method currentMethod = class_getInstanceMethod([self class], currentSEL);
method_exchangeImplementations(originMethod, currentMethod);
}
- (UIViewController *)wp_popViewControllerAnimated:(BOOL)animated{
extern const char *WPVCPOPFLAG;
UIViewController *popViewController = [self wp_popViewControllerAnimated:animated];
objc_setAssociatedObject(popViewController, WPVCPOPFLAG, @(YES), OBJC_ASSOCIATION_ASSIGN);
return popViewController;
}
@end
我们存在循环引用的代码:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.str = @"123";
self.block = ^{
NSLog(@"%@",self.str);
};
// Do any additional setup after loading the view.
}
2019-01-02 18:12:47.991684+0800 CustomLeakTest[42603:920435] TestViewController IS NOT DELLOC
最后附上demo地址:https://github.com/gnaw9258wp/CustomLeak.git
网友评论