美文网首页
MLeaksFinder 浅析

MLeaksFinder 浅析

作者: 朽木自雕也 | 来源:发表于2018-10-22 22:24 被阅读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原理分析

    相关文章

      网友评论

          本文标题:MLeaksFinder 浅析

          本文链接:https://www.haomeiwen.com/subject/vomnzftx.html