1. 程式人生 > >利用RunTime解決由NSTimer導致的記憶體洩漏

利用RunTime解決由NSTimer導致的記憶體洩漏

NSTimer使用場景

NSTimer來實現每隔一定時間執行制定的任務,例如最常見的廣告輪播圖,使用NSTimer實現這個功能很簡單程式碼如下

    NSTimer *_timer;
    _timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerEvent) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];

但是要記住只要觸發了計時器這種操作在不用時一定要把計時器終止掉

[_timer invalidate];

一般我們終止這個操作都需要在這個介面銷燬時。但是我們在初始化NSTimer時指定了觸發事件為self,所以說selfNSTimer強引用了,而NSTimer物件又被加入了當前的迴圈中,所以說NSTimer被 Runloop 強引用了,所以導致self不會被釋放掉就不會觸發dealloc方法
實際上想這樣操作

-(void)dealloc
{
    [_timer invalidate];
}

但是由於self物件被持有,所有不會走dealloc,導致雖然已經退出當前介面了,但是計時器還是一致再執行,出現記憶體洩漏。

解決方法

思路很簡單,初始化NSTimer時把觸發事件的target替換成一個單獨的物件,然後這個物件中NSTimerSEL方法觸發時讓這個方法在當前的檢視self中實現。
利用RunTimetarget物件中動態的建立SEL方法,然後target物件關聯當前的檢視self,當target物件執行SEL方法時,取出關聯物件self,然後讓self執行該方法。
實現程式碼

@interface TableViewController ()
@property (nonatomic,strong) id timerTarget;
@end
static const void * TimerKey = @"TimerKey"
; static const void * weakKey = @"weakKey"; @implementation TableViewController - (void)viewDidLoad { [super viewDidLoad]; _timerTarget = [NSObject new]; //初始化timerTarge物件 class_addMethod([_timerTarget class], @selector(timerEvent), (IMP)timMethod, "[email protected]:"); //動態建立timerEvent方法 NSTimer *_timer; _timer = [NSTimer timerWithTimeInterval:1 target:_timerTarget selector:@selector(timerEvent) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; //建立計時器target物件為_timerTarget objc_setAssociatedObject(_timerTarget, TimerKey, _timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(_timerTarget, weakKey, self, OBJC_ASSOCIATION_ASSIGN); //將self物件與NSTimer物件與_timerTarget物件關聯 } void timMethod(id self,SEL _cmd) { TableViewController *tabview = objc_getAssociatedObject(self, weakKey); [tabview performSelector:_cmd]; } -(void)timerEvent { NSLog(@"%@",NSStringFromClass([self class])); } -(void)dealloc { NSTimer *timer = objc_getAssociatedObject(_timerTarget, TimerKey); [timer invalidate]; NSLog(@"%@--dealloc",NSStringFromClass([self class])); }

這樣當檢視銷燬時因為當前檢視不被任何物件所持有,所以會走dealloc方法,然後NSTimer執行invalidate也被銷燬釋放掉了。

說明

objc_setAssociatedObject(_timerTarget, weakKey, self,OBJC_ASSOCIATION_ASSIGN);

在把_timerTargetself關聯時關聯的屬性一定要設定為OBJC_ASSOCIATION_ASSIGNOBJC_ASSOCIATION_ASSIGN為弱指標型別,如果設定為強制針,那麼self_timerTarget就會發生相互強引用但是記憶體不能正確釋放。

關於使用到的Runtime

 class_addMethod([_timerTarget class], @selector(timerEvent), (IMP)timMethod, "[email protected]:");

動態的為類新增一個timerEventObjective-C方法,這個方法是由CtimMethod方法來實現的

void timMethod(id self,SEL _cmd)
{
    TableViewController *tabview = objc_getAssociatedObject(self, weakKey);
    [tabview performSelector:_cmd];
}

該方法是取到_timerTarget關聯的物件,然後讓該物件去執行timerEvent方法。
"[email protected]:"是方法的引數,關於引數解釋參考Objective-C type encodings

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

objc_getAssociatedObject(id object, const void *key)

這組方法是設定關聯物件與獲取關聯物件key是關聯物件的key

相關推薦

利用RunTime解決NSTimer導致記憶體洩漏

NSTimer使用場景 用NSTimer來實現每隔一定時間執行制定的任務,例如最常見的廣告輪播圖,使用NSTimer實現這個功能很簡單程式碼如下 NSTimer *_timer; _timer = [NSTimer timerWithTi

iOS開發使用 runtime 方法中的 class_copyIvarList,class_copyMethodList 方法時導致記憶體洩漏問題

前段時間在做公司新專案的時候使用了 runtime 的  class_copyIvarList 方法來獲取類的所有屬性的時候,用 leaks 檢測,發現這裡出現了記憶體洩漏。後來查了一些資料發現 class_copyIvarList 返回的物件需要手動釋放。因

使用Glide導致記憶體洩漏最終OOM的問題解決

前兩天在專案的測試過程中出現了不規律崩潰的情況,檢視堆疊資訊是OOM導致的崩潰,但是在程式碼中沒有載入大檔案之類的操作,所以懷疑是記憶體洩漏導致的 ;(關於如何檢視記憶體資訊和某一時刻記憶體中物件(資料

java內部類實現(可能導致記憶體洩漏

在使用java內部類的時候要注意可能引起的記憶體洩漏 程式碼如下 package com.example; public class MyClass { public static void main(String[] args) throws Throwab

Handler原始碼詳解及導致記憶體洩漏的分析

[TOC] 簡介 android的訊息處理有三個核心類:Looper,Handler和Message, 主要接受子執行緒傳送的資料, 並用此資料配合主執行緒更新UI。 部分圖片來至CodingMyWorld部落格,3Q 使用方法 pu

記憶體洩漏優化---靜態變數導致記憶體洩漏

1、要不怎麼說static關鍵字要慎用呢?來看看下面這段程式碼,Context物件為靜態的,那麼Activity就無法正常銷燬,會常駐記憶體。 public class MainActivity extends Activity{ public static Conte

基於Kotlin解決Android中Handler記憶體洩漏問題

作為Android開發者,我們都知道,當我們在子執行緒處理完耗時任務後重新整理UI時,一般會藉助於 Handler 來實現。關於handler具體用法這裡不做說明了,在使用 Handler 時一般會遇到記憶體洩漏的隱患,同時編譯器也會給出一大片黃色的警告,在兩者

單列模式導致記憶體洩漏

Android中常見的記憶體洩漏彙總 集合類洩漏 集合類如果僅僅有新增元素的方法,而沒有相應的刪除機制,導致記憶體被佔用。如果這個集合類是全域性性的變數 (比如類中的靜態屬性,全域性性的 map 等即有靜態引用或 final 一直指向它),那麼沒有相應的刪除

Android —— 解決MVP引起的記憶體洩漏

首先不瞭解MVP模式的孩紙先去看一下MVP再閱讀本部落格嘍。 使用MVP模式的主要作用,是它解決了業務邏輯和資料存取的緊耦合,使Presenter作為view和model的中間人,降低了資料和view的耦合度。所以MVP有很多有點:利於維護、易於測試、鬆耦合、

什麼情況下會導致記憶體洩漏

在使用listview的時候通常使用Adapter,那麼 我們應該儘可能的使用ConvertView。為什麼要複用ConvertView?當ContertView為空時,用setTag()方法為每一個View繫結一個存放控制元件的ViewHolder物件,當convertVIew不為空,重複利用已經建立的vi

利用runtime解決button重複響應事件

該方法靈感來自於簡書《[iOS]利用runtime,解決多次點選相同button,導致重複跳轉的問題》 場景 1.當app有點卡的時候,多次點選相同的button,經常出現,跳轉了N次相同的介面。 2.當網路較差時,多次點選相同按鈕,會造成資料的重複提交或請求。 3..

Android導致記憶體洩漏的幾種情形

集合類 集合類如果僅僅有新增元素的方法,而沒有相應的刪除機制,導致記憶體被佔用。如果這個集合類是全域性性的變數(比如類中的靜態屬性,全域性性的map等即有靜態引用或final一直指向它),那麼沒有相應的刪除機制,很可能導致集合所佔用的記憶體只增不減。 單

頻繁通過win32api的createfile函式開啟檔案控制代碼導致記憶體洩漏

1、通過win32的createfile、writefile函式開啟寫入檔案 void WriteLogThread(void* lpParameter) { LPLogData pData = (LPLogData)lpParameter; string logCon

利用NSProxy解決NSTimer記憶體洩漏問題

之前寫過一篇利用RunTime解決由NSTimer導致的記憶體洩漏的文章,最近和同事討論覺得這樣寫有點複雜,然後發現有NSProxy這麼好用的根類,根類,根類,沒錯NSProxy與NSObject一樣是

Android---解決WebView導致記憶體洩漏

如何解決WebView導致的記憶體洩漏 懶得廢話: 1.避免在xml佈局檔案中直接巢狀webview控制元件,而是採用addview的方式new一個webview並載入到佈局中,如: w

框架或者程式用了Introspector類導致記憶體洩漏問題解決方案

在web.xml檔案中加入如下配置: <!-- 重新整理Introspector防止記憶體洩露 --> <listener>         <listener-class>org.springframework.web.util.In

講述Sagit.Framework解決:雙向引用導致的IOS記憶體洩漏(下)- block中任性用self

前言: 發現業務程式碼有一個地方的記憶體沒釋放,原因很也簡單: 在block裡用到了self,造成雙向引用,然後就開始思考怎麼處理這個問題。 常規則思維,就是改程式碼,block不要用到self,或只用self的弱引用。 只是框架這裡特別,有一個特好用的系列,STLastXXX系列,是用巨集定

講述Sagit.Framework解決:雙向引用導致的IOS記憶體洩漏(上)

前言: 好久沒寫文章了,最近先是重構IT戀、又重寫IT戀中。 Sagit框架也不斷的更新,調整,現在感覺已完美了了相當的多。 今天不寫教程,先簡單分享一下技術內容。 1:見Block必有:#define WeakSelf __weak typeof(self) this = self;  故事要從這

講述Sagit.Framework解決:雙向引用導致的IOS記憶體洩漏(中)- IOS不為人知的Bug

前言: 文章寫到最後時,多了很多莫名奇妙的問題!!! 為了解決了這些莫名奇妙的問題,我又戰鬥了24小時〜〜〜 然後終於解決了問題,原來是IOS的隱藏性Bug,只想恨恨的說一聲fuck~~~ 故事起源: 故事是這樣的,為了處理記憶體釋放的問題,正常人的思維,都是給物件的dealloc增加日誌輸出。

記一次Dubbo導致記憶體洩漏過程分析及解決

       近日測試團隊反饋版本機測試環境請求經常卡頓,十分緩慢,甚至有超時的情況,但是請求返回、業務邏輯均是正常的,因此進行了一番排查。         首先檢視應用日誌,及控制檯監控,應用均表現無異常,由於版本