iOS 自定义一个简易内存检测工具

也是在看过开源代码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

你可能感兴趣的