MLeaksFinder 浅析

2018-10-22  本文已影响17人  朽木自雕也

MLeaksFinder 框架

MLeaksFinder 提供了iOS内存泄露检测非常好的解决方案。

1.只需要引入 MLeaksFinder,就可以自动在 App 运行过程检测到内存泄露的对象并立即提醒,

2.无需打开额外的工具。

3.也无需为了检测内存泄露而一个个场景去重复地操作。

MLeaksFinder开源地址

更专业的文档说明,可以好好研究研究,我这里就不做过多的抄袭

实现的大概思路:在视图控制器弹出栈 && 视图完全消失时。

创建一个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原理分析

上一篇下一篇

猜你喜欢

热点阅读