在iOS開發(fā)中首頁展示廣告欄河胎,并定時驅(qū)動的展示效果很常見偷线,就目前我經(jīng)手的項目來看,多數(shù)有這種展示锋恬,這種是需要用定時器驅(qū)動的,然基本沒有人考慮到NSTimer使用造成的循環(huán)引用問題慎式,特別是對于一些需要切換框架的App伶氢,頻繁的切換框架趟径,造成頻繁的創(chuàng)建新框架,原框架由于和NSTimer相互引用無法銷毀癣防,造成內(nèi)存增長蜗巧,閑話不多說,進(jìn)入正題:
一般情況下創(chuàng)建定時器的方法:
- (NSTimer *)verifyTimer{
if (!_verifyTimer) {//立刻執(zhí)行
_verifyTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(verifyTimerAction:) userInfo:nil repeats:YES];
}
return _verifyTimer;
}
self.timer = [NSTimer timerWithTimeInterval:3.0f target:self selector:@selector(timer:) userInfo:nil repeats:YES]
//加入runloop后立即執(zhí)行
[[NSRunLoop currentRunLoop] addTimer:self.bannerTimer forMode:NSRunLoopCommonModes];
在這里不對每個參數(shù)過多介紹蕾盯,就上邊的兩種創(chuàng)建方式看幕屹,都存在循環(huán)引用的情況
一般我們在使用NSTimer時都會把它當(dāng)做一個屬性來使用,NSTimer被self引用级遭,在重復(fù)調(diào)用方法時望拖,將self作為target,這時NSTimer會獲取保留self挫鸽,此時就會造成循環(huán)引用使self和NSTimer都不能銷毀说敏,當(dāng)然我們可以在銷毀self之前使用以下兩句銷毀NSTimer
[self.verifyTimer invalidate];
self.verifyTimer = nil;
然不是所有開發(fā)者都這么注意此處的循環(huán)引用問題,廢話不多說丢郊,直接上代碼盔沫,讓我們對使用方法做一下處理
__weak __typeof(&*self)ws = self;
if (self.bannerTimer == nil) {//此處必須加判斷,若是重復(fù)創(chuàng)建加入runloop枫匾,則會同時進(jìn)行若干個timer架诞,廣告切換則會加快
self.bannerTimer = [NSTimer block_TimerWithTimeInterval:3.0f block:^{
[ws nextPageAction];
} repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.bannerTimer forMode:NSRunLoopCommonModes];
}
使用上述方法需要創(chuàng)建NSTimer的分類
#import <Foundation/Foundation.h>
@interface NSTimer (TimerBlockSuport)
/**
分類解決NSTimer在使用時造成的循環(huán)引用的問題
@param interval 間隔時間
@param block 回調(diào)
@param reqeats 是否立刻執(zhí)行
@return 返回NSTimer實體
*/
+ (NSTimer *)block_TimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)reqeats;
@end
#import "NSTimer+TimerBlockSuport.h"
@implementation NSTimer (TimerBlockSuport)
+ (NSTimer *)block_TimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)reqeats{
return [self timerWithTimeInterval:interval target:self selector:@selector(blockinvoke:) userInfo:[block copy] repeats:reqeats];
}
+ (void)blockinvoke:(NSTimer *)timer{
void (^block)() = timer.userInfo;
if (block) {
block();
}
}
上述創(chuàng)建方式我們方法的調(diào)用者是NSTImer自己,只是NSTimer捕獲了參數(shù)block干茉,若是block中也是用self調(diào)用方法的話谴忧,也會造成循環(huán)引用,我們這里將self弱引用角虫,這樣NSTimer不會捕獲self的強引用沾谓,巧妙的避開了循環(huán)引用。
小坑:
在使用時遇到一個小問題上遥,在使用定時器時搏屑,我沒有判斷屬性NSTimer是否為nil,導(dǎo)致多次對屬性NSTImer賦值粉楚,造成runloop中有多個調(diào)用同一個方法的NSTimer在跑辣恋,導(dǎo)致重復(fù)執(zhí)行時間間隔變小的問題,在這提醒一下模软,使用時切記判斷是否為nil