Demo 下载
尽管我们现在有了 ARC.但是内存泄漏一直都是一个不可避免的话题.
我们可以通过 xcode 提供的工具,以及第三方来实现内存泄漏的检测.但是如果要我们自己来实现一个简单的内存检测工具应该如何实现呢?
先看一下效果:
提供一下思路:
内存是否泄漏, 一个很普遍的现象就是,在导航控制器 pop 之后, vc 还存在. 如果我们检测到了在 pop 之后还存在,那么就可以发出警告, 内存泄漏.
为了达到监听 所有 vc 的 pop, 我们使用的方式是在 UIViewController 的分类里面利用 runtime来实现.
跟着我的节奏来
1: 交换viewWillAppear, viewDidDisappear
#import "UIViewController+Extension.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "NSObject+Extension.h"
NSInteger key = 9999;
@interface UIViewController ()
@end
@implementation UIViewController (Extension)
//在 load 方法里面做方法的交换
//交换 viewWillAppear 是为了得知当前 vc页面消失是 pop 还是 push, 我们的需求是在 pop 的时候检测, 在viewWillAppear 设置一个标志
//交换viewDidDisappear 是为了知道 当前 vc 已经 pop 成功了, 这个时候就可以查看当前 vc 是否还存在来检测是否内存泄漏
+ (void)load {
Method orgMethod = class_getInstanceMethod(self, @selector(viewWillAppear:));
Method swzzMethod = class_getInstanceMethod(self, @selector(lg_viewWillAppear:));
method_exchangeImplementations(orgMethod, swzzMethod);
Method org2Method = class_getInstanceMethod(self, @selector(viewDidDisappear:));
Method swzz2Method = class_getInstanceMethod(self, @selector(lg_viewDidDisappear:));
method_exchangeImplementations(org2Method, swzz2Method);
}
//即将显示
-(void)lg_viewWillAppear:(BOOL)animated {
[self lg_viewWillAppear:animated];
//设置 key 为 NO, 如果设置为 对应的值变成了 YES, 那么我们认为是 pop, 这只是一个标识
objc_setAssociatedObject(self, &key,@(NO) , OBJC_ASSOCIATION_ASSIGN);
}
//页面消失, 并且 是 pop 那么去检测当前 vc 的情况
-(void)lg_viewDidDisappear:(BOOL)animated {
[self lg_viewDidDisappear:animated];
//如果是 pop
if ([objc_getAssociatedObject(self, &key) boolValue]) {
//检测是否内存泄漏
[self lg_delloc];
}
}
@end
2: 那我们在什么时候把 key 的值设置为 yes,认为是 pop 呢
那这个时候我们就要利用到 UINavigationController了. 同样的我们需要监听所有的popViewControllerAnimated. 那我们利用 runtime 实行对方法的交换
#import "UINavigationController+Extension.h"
#import <objc/runtime.h>
#import <objc/message.h>
@implementation UINavigationController (Extension)
+ (void)load
{
Method orgMethod = class_getInstanceMethod(self, @selector(popViewControllerAnimated:));
Method swzzMethod = class_getInstanceMethod(self, @selector(lg_popViewControllerAnimated:));
method_exchangeImplementations(orgMethod, swzzMethod);
}
- (UIViewController *)lg_popViewControllerAnimated:(BOOL)animated {
UIViewController *vc = [self lg_popViewControllerAnimated:animated];
extern NSInteger key;
objc_setAssociatedObject(vc, &key,@(YES) , OBJC_ASSOCIATION_ASSIGN);
return vc;
}
@end
最后一步: 检测
检测的思路很简单, 在 viewDidDissappear 后,延时0.5秒, 如果 vc 还存在我们认为内存泄漏, 反之没有泄漏
#import "NSObject+Extension.h"
#import <UIKit/UIKit.h>
@implementation NSObject (Extension)
//第一种 当 vc diddissappear 后调用 输出是空
-(void)lg_delloc {
__weak typeof(self)weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (weakSelf != nil) {
NSLog(@"内存泄漏了");
} else {
NSLog(@"内存没有泄漏");
}
});
}
@end