iOS解決NSTimer的循環(huán)引用問題

NSTimer是iOS中常用的定時器,通常用來在固定時間間隔重復(fù)某個任務(wù)傲茄。使用起來也比較簡單更舞,但是一直以來存在一個問題,就是會造成循環(huán)引用入热,下面先來看下導(dǎo)致循環(huán)引用的用法。

假設(shè)現(xiàn)在有一個控制器疲迂。

@interface MyViewController ()
@property (nonatomic, strong) NSTimer * timer;
@end

在控制器的viewDidLoad中才顿,我們初始化一個按鈕。

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn setTitle:@"begin" forState:UIControlStateNormal];
    [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    btn.frame = CGRectMake(20, 100, 120, 80);
    [btn addTarget:self action:@selector(update) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
}

點擊按鈕尤蒿,初始化timer郑气。

- (void)update {
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(logNumber) userInfo:nil repeats:YES];
}

每隔2秒執(zhí)行以下方法。

- (void)logNumber {
    NSLog(@"22222");
}

看起來很簡單腰池,代碼也可以順利運行尾组,但是問題來了,timer作為控制的屬性示弓,初始化時讳侨,控制器強引用timer,在timer的初始化方法中奏属,self(即控制器)又作為targettimer強引用跨跨,毫無疑問,一個循環(huán)引用出現(xiàn)了囱皿,這將導(dǎo)致兩者都不能被釋放勇婴,也就是說,控制器在被推出的時候嘱腥,并不會執(zhí)行dealloc方法耕渴,因此,下面的方法也就不會執(zhí)行齿兔。timer自然也不會被釋放橱脸。

- (void)dealloc {     
    [self.timer invalidate];
    self.timer = nil;
}

那要怎么解決呢础米?這里介紹一種方法,引入中間者添诉。
MyTimerMiddle是一個中間類屁桑,它主要負(fù)責(zé)timer的初始化,定時任務(wù)的觸發(fā)以及timer的銷毀吻商,同時掏颊,也負(fù)責(zé)連接起最終要執(zhí)行任務(wù)的目標(biāo)對象。

@interface MyTimerMiddle : NSObject
// target即是最終要連接的目標(biāo)對象艾帐,注意:這里使用weak,原因后面會說明盆偿。
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;

- (instancetype)initWithTimeInterval:(NSTimeInterval)interval
                              target:(id)target
                            selector:(SEL)selector;
// 銷毀timer
- (void)cleanup;
@end

timer作為它的一個屬性柒爸。

#import "MyTimerMiddle.h"

@interface MyTimerMiddle ()
@property (nonatomic, strong) NSTimer * timer;
@end

對外提供一個自定義的初始化方法

- (instancetype)initWithTimeInterval:(NSTimeInterval)interval
                              target:(id)target
                            selector:(SEL)selector {
    if (self = [super init]) {
        self.target = target;
        self.selector = selector;
        self.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(fetchData:) userInfo:nil repeats:YES];
    }
    return self;
}

定時執(zhí)行的任務(wù),這里模擬了一個下載任務(wù)事扭,3秒后回到主線程執(zhí)行捎稚,這里是真正連接目標(biāo)對象的地方。

- (void)fetchData:(NSTimer *)timer {
    NSLog(@"開始下載.....");
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        __strong typeof(self) sself = weakSelf;
        if (!sself) {
            return;
        }
        if (sself.target == nil) {
            return;
        }
        id targrt = sself.target;
        SEL selector = sself.selector;
        if ([targrt respondsToSelector:selector]) {
            [targrt performSelector:selector withObject:@{@"name": @"mike"}];
        }
    });
}

接下來是timer的銷毀方法求橄。

- (void)cleanup {
    [self.timer invalidate];
    self.timer = nil;
}

使用的時候今野,我們在目標(biāo)控制器里聲明一個中間者類型的屬性。

@interface MyViewController ()
@property (nonatomic, strong) MyTimerMiddle * timerMid;
@end

初始化中間類罐农,注意条霜,這里的taerget指定為self,因為之前聲明target屬性的時候用的是weak涵亏,因此這里中間類并沒有強引用self宰睡,從而避免了循環(huán)引用。showSome即是目標(biāo)對象最終要定時執(zhí)行的任務(wù)气筋。

self.timerMid = [[MyTimerMiddle alloc] initWithTimeInterval:5 target:self selector:@selector(showSome:)];

最后拆内,我們需要在控制器銷毀時對中間類進(jìn)行清理工作。

- (void)dealloc {
    NSLog(@"111");
    [self.timerMid cleanup];
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宠默,一起剝皮案震驚了整個濱河市麸恍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搀矫,老刑警劉巖抹沪,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異艾君,居然都是意外死亡采够,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門冰垄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹬癌,“玉大人权她,你說我怎么就攤上這事∈判剑” “怎么了隅要?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長董济。 經(jīng)常有香客問我步清,道長,這世上最難降的妖魔是什么虏肾? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任廓啊,我火速辦了婚禮,結(jié)果婚禮上封豪,老公的妹妹穿的比我還像新娘谴轮。我一直安慰自己,他們只是感情好吹埠,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布第步。 她就那樣靜靜地躺著,像睡著了一般缘琅。 火紅的嫁衣襯著肌膚如雪粘都。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天刷袍,我揣著相機(jī)與錄音翩隧,去河邊找鬼。 笑死做个,一個胖子當(dāng)著我的面吹牛鸽心,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播居暖,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼顽频,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了太闺?” 一聲冷哼從身側(cè)響起糯景,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎省骂,沒想到半個月后蟀淮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡钞澳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年怠惶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轧粟。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡策治,死狀恐怖脓魏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情通惫,我是刑警寧澤茂翔,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站履腋,受9級特大地震影響珊燎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遵湖,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一悔政、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧延旧,春花似錦卓箫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闷盔。三九已至弯洗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間逢勾,已是汗流浹背牡整。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留溺拱,地道東北人逃贝。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像迫摔,于是被迫代替她去往敵國和親沐扳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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