第52條:別忘了NSTimer會保留其目標(biāo)對象

NSTimer(計(jì)時(shí)器)是一種很方便很有用的對象岛请,可以指定絕對的日期與時(shí)間压怠,以便到時(shí)執(zhí)行任務(wù)掐场,也可以指定執(zhí)行執(zhí)行任務(wù)的相對延遲時(shí)間,還可以重復(fù)運(yùn)行任務(wù)旋膳,設(shè)定“間隔值”用來指定任務(wù)的觸發(fā)頻率澎语。

計(jì)時(shí)器要和運(yùn)行循環(huán)相關(guān)聯(lián),運(yùn)行循環(huán)到時(shí)候會觸發(fā)任務(wù)。只有把計(jì)時(shí)器放到運(yùn)行循環(huán)里咏连,它才能正常觸發(fā)任務(wù)盯孙。例如,下面這個(gè)方法可以創(chuàng)建計(jì)時(shí)器祟滴,并將其預(yù)先安排在當(dāng)前運(yùn)行循環(huán)中:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;

此方法創(chuàng)建出來的計(jì)時(shí)器,會在指定的間隔時(shí)間之后執(zhí)行任務(wù)振惰。也可以令其反復(fù)執(zhí)行任務(wù),直到開發(fā)者稍后將其手動關(guān)閉為止垄懂。target和selector表示在哪個(gè)對象上調(diào)用哪個(gè)方法骑晶。執(zhí)行完任務(wù)后,一次性計(jì)時(shí)器會失效草慧,若repeats為YES桶蛔,那么必須調(diào)用invalidate方法才能使其停止。

重復(fù)執(zhí)行模式的計(jì)時(shí)器漫谷,很容易引入保留環(huán):

@interface EOCClass : NSObject
- (void)startPolling;
- (void)stopPolling;
@end

@implementation EOCClass{
    NSTimer *_poliTimer;
}

- (id) init{
    return [super init];
}

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

- (void)stopPolling{
    [_poliTimer invalidate];
    _poliTimer = nil;
}

- (void)startPolling{
    _poliTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(p_doPoll) userInfo:nil repeats:YES];
}

- (void)p_doPoll{
    // code
}

如果創(chuàng)建了本類實(shí)例仔雷,并調(diào)用了startPolling方法。創(chuàng)建計(jì)時(shí)器的時(shí)候舔示,由于目標(biāo)對象是self碟婆,所以要保留此實(shí)例。然而惕稻,因?yàn)橛?jì)時(shí)器是用實(shí)例變量存放的竖共,所以實(shí)例也保留了計(jì)數(shù)器,于是就產(chǎn)生了保留環(huán)俺祠。

調(diào)用stopPolling方法或令系統(tǒng)將實(shí)例回收(會自動調(diào)用dealloc方法)可以使計(jì)時(shí)器失效公给,從而打破循環(huán),但無法確保stopPolling方法一定調(diào)用蜘渣,而由于計(jì)時(shí)器保存著實(shí)例淌铐,實(shí)例永遠(yuǎn)不會被系統(tǒng)回收。當(dāng)EOCClass實(shí)例的最后一個(gè)外部引用移走之后蔫缸,實(shí)例仍然存活腿准,而計(jì)時(shí)器對象也就不可能被系統(tǒng)回收,除了計(jì)時(shí)器外沒有別的引用再指向這個(gè)實(shí)例捂龄,實(shí)例就永遠(yuǎn)丟失了,造成內(nèi)存泄漏加叁。

解決方案是采用塊為計(jì)時(shí)器添加新功能:

@interface NSTimer (EOCBlocksSupport)
+ (NSTimer*)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;
@end

@implementation NSTimer( EOCBlocksSupport)

+ (NSTimer*)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)repeats{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(eoc_blockInvoke:) userInfo:[block copy] repeats:repeats];
}

+ (void)eoc_blockInvoke:(NSTimer*)timer{
    void (^block)() = timer.userInfo;
    if (block) {
        block();
    }
}

再修改stopPolling方法:

- (void)startPolling{
    __weak EOCClass *weakSelf = self;
    _poliTimer = [NSTimer eoc_scheduledTimerWithTimeInterval:5.0 block:^{
        EOCClass *strongSelf = weakSelf;
        [strongSelf p_doPoll];
    } repeats:YES];
}

這段代碼先定義了一個(gè)弱引用指向self倦沧,然后用塊捕獲這個(gè)引用,這樣self就不會被計(jì)時(shí)器所保留它匕,當(dāng)塊開始執(zhí)行時(shí)展融,立刻生成strong引用,保證實(shí)例在執(zhí)行器繼續(xù)存活豫柬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末告希,一起剝皮案震驚了整個(gè)濱河市扑浸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌燕偶,老刑警劉巖喝噪,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異指么,居然都是意外死亡酝惧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門伯诬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晚唇,“玉大人,你說我怎么就攤上這事盗似×ㄉ拢” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵赫舒,是天一觀的道長悍及。 經(jīng)常有香客問我,道長号阿,這世上最難降的妖魔是什么并鸵? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮扔涧,結(jié)果婚禮上园担,老公的妹妹穿的比我還像新娘。我一直安慰自己枯夜,他們只是感情好弯汰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著湖雹,像睡著了一般咏闪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上摔吏,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天鸽嫂,我揣著相機(jī)與錄音,去河邊找鬼征讲。 笑死据某,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诗箍。 我是一名探鬼主播癣籽,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了筷狼?” 一聲冷哼從身側(cè)響起瓶籽,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎埂材,沒想到半個(gè)月后塑顺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楞遏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年茬暇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寡喝。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡糙俗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出预鬓,到底是詐尸還是另有隱情巧骚,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布格二,位于F島的核電站劈彪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏顶猜。R本人自食惡果不足惜沧奴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望长窄。 院中可真熱鬧滔吠,春花似錦、人聲如沸挠日。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嚣潜。三九已至冬骚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懂算,已是汗流浹背只冻。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留计技,地道東北人喜德。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像酸役,于是被迫代替她去往敵國和親住诸。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

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