iOS 高級開發(fā)(4)之 內(nèi)存檢測工具的簡單實(shí)現(xiàn)

Demo 下載
盡管我們現(xiàn)在有了 ARC.但是內(nèi)存泄漏一直都是一個不可避免的話題.
我們可以通過 xcode 提供的工具,以及第三方來實(shí)現(xiàn)內(nèi)存泄漏的檢測.但是如果要我們自己來實(shí)現(xiàn)一個簡單的內(nèi)存檢測工具應(yīng)該如何實(shí)現(xiàn)呢?
先看一下效果:

內(nèi)存沒有泄漏.png

內(nèi)存泄漏.png

提供一下思路:
內(nèi)存是否泄漏, 一個很普遍的現(xiàn)象就是,在導(dǎo)航控制器 pop 之后, vc 還存在. 如果我們檢測到了在 pop 之后還存在,那么就可以發(fā)出警告, 內(nèi)存泄漏.
為了達(dá)到監(jiān)聽 所有 vc 的 pop, 我們使用的方式是在 UIViewController 的分類里面利用 runtime來實(shí)現(xiàn).
跟著我的節(jié)奏來
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 是為了得知當(dāng)前 vc頁面消失是 pop 還是 push, 我們的需求是在 pop 的時候檢測,  在viewWillAppear 設(shè)置一個標(biāo)志
//交換viewDidDisappear 是為了知道 當(dāng)前 vc 已經(jīng) pop 成功了, 這個時候就可以查看當(dāng)前 vc 是否還存在來檢測是否內(nèi)存泄漏
+ (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];
    //設(shè)置 key 為 NO,  如果設(shè)置為 對應(yīng)的值變成了 YES, 那么我們認(rèn)為是 pop, 這只是一個標(biāo)識
    
    objc_setAssociatedObject(self, &key,@(NO) , OBJC_ASSOCIATION_ASSIGN);
}
//頁面消失, 并且 是 pop 那么去檢測當(dāng)前 vc 的情況
-(void)lg_viewDidDisappear:(BOOL)animated {
    [self lg_viewDidDisappear:animated];
    //如果是 pop
    if ([objc_getAssociatedObject(self,  &key) boolValue]) {
        //檢測是否內(nèi)存泄漏
        [self lg_delloc];
    }
}

@end

2: 那我們在什么時候把 key 的值設(shè)置為 yes,認(rèn)為是 pop 呢
那這個時候我們就要利用到 UINavigationController了. 同樣的我們需要監(jiān)聽所有的popViewControllerAnimated. 那我們利用 runtime 實(shí)行對方法的交換

#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 還存在我們認(rèn)為內(nèi)存泄漏, 反之沒有泄漏

#import "NSObject+Extension.h"
#import <UIKit/UIKit.h>
@implementation NSObject (Extension)
//第一種   當(dāng) vc  diddissappear  后調(diào)用  輸出是空
-(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(@"內(nèi)存泄漏了");
        } else {
            NSLog(@"內(nèi)存沒有泄漏");
        }
     });
}
@end

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容