MLeaksFinder 框架
MLeaksFinder 提供了iOS内存泄露检测非常好的解决方案。
1.只需要引入 MLeaksFinder,就可以自动在 App 运行过程检测到内存泄露的对象并立即提醒,
2.无需打开额外的工具。
3.也无需为了检测内存泄露而一个个场景去重复地操作。
更专业的文档说明,可以好好研究研究,我这里就不做过多的抄袭
实现的大概思路:在视图控制器弹出栈 && 视图完全消失时。
创建一个NSObject的分类,提供简便的方法交换类方法:
#import "NSObject+JXRuntime.h"
#import<objc/runtime.h>
@implementation NSObject (JXRuntime)
+(void)swizzleSEL:(SEL)originalSEL withSEL:(SEL)swizzledSEL{
Class class = [self class];
Method originalMethod = class_getInstanceMethod(class, originalSEL);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL);
BOOL didAddMethod = class_addMethod(class, originalSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
//若类没有实现需要被替换的原方法,也就是上一步添加原方法成功,此时已将本来要swizzle的方法的实现直接复制进原方法里。
//还需要把新方法IMP指向原方法的实现:
if (didAddMethod) {
class_replaceMethod(class, swizzledSEL, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
//类有对应的原方法,则正常交换
else{
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
新建UIViewController分类,交换viewWillAppear:和viewDidDisappear:方法
#import "UIViewController+Leaks.h"
#import "NSObject+JXRuntime.h"
#import <objc/runtime.h>
const void *const kHasBeenPoppedKey = "kHasBeenPoppedKey";//标记是否已经出栈
@implementation UIViewController (Leaks)
+ (void)load{
//正常情况load只会执行一次,使用dispatch_once是为了防止人为调用load方法
//在load方法而不是在initalize方法中进行交换的原因:(1)load在类被加载时调用,initalize在类或其子类收到第一条消息时才被调用,类似懒加载。(2)load方法在父类、子类、分类中是独立的
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleSEL:@selector(viewWillAppear:) withSEL:@selector(swizzled_viewWillAppear:)];
[self swizzleSEL:@selector(viewDidDisappear:) withSEL:@selector(swizzled_viewDidDisappear:)];
});
}
- (void) swizzled_viewWillAppear:(BOOL) animated{
[self swizzled_viewWillAppear:animated];
//标记为进栈
objc_setAssociatedObject(self, kHasBeenPoppedKey, @(NO), OBJC_ASSOCIATION_RETAIN);
}
-(void) swizzled_viewDidDisappear:(BOOL) animated{
[self swizzled_viewDidDisappear:animated];
//已经出栈
if ([objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue] == YES) {
//判断对象是否被销毁
[self willDealloc];
}
}
新建UINavigationController分类,交换popViewControllerAnimated:方法
#import "UINavigationController+Leaks.h"
#import <objc/runtime.h>
#import "NSObject+JXRuntime.h"
@implementation UINavigationController (Leaks)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleSEL:@selector(popViewControllerAnimated:) withSEL:@selector(swizzled_popViewControllerAnimated:)];
});
}
- (UIViewController*)swizzled_popViewControllerAnimated:(BOOL)animated{
UIViewController *poppedViewController = [self swizzled_popViewControllerAnimated:animated];
extern const void * const kHasBeenPoppedKey;
//标记为已经出栈
objc_setAssociatedObject(poppedViewController, kHasBeenPoppedKey, @(YES), OBJC_ASSOCIATION_RETAIN);
return poppedViewController;
}
@end
参考文章: MLeaksFinder原理分析
网友评论