iOS如何安全而又優(yōu)雅的使用NSTimer

如何安全而又優(yōu)雅的使用一個NSTimer?
請往下看??

使用NSTimer最大的困擾就是在于必須手動釋放掉這個被我們創(chuàng)建的timer妆够,然而由于我們的粗心,很大可能忘記了去手動釋放

 [self.timer invalidate];
 self.timer = nil;

然而有時候我們卻忘記了該在什么時機去釋放呢?

  • 我們很聰明的在dealloc中寫下代碼负蚊,自以為完美無缺的代碼
- (void)dealloc {
    [self.timer invalidate];
    self.timer = nil;
}

too young too simple神妹,在dealloc中添加

NSLog(@"======= ViewController dealloc =======");

神奇的發(fā)現(xiàn),居然沒有打印家妆,wtf ?? ??

于是乎鸵荠,各種面向搜索引擎,找到了本篇文章~
如何安全而又優(yōu)雅的使用NSTimer

先來分析下引起循環(huán)印用的原因:

假設我們在viewController中寫下這樣的代碼時

[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(increaseLabel) userInfo:nil repeats:YES];

此時 timer->self->timer揩徊,selftimer釋放掉才能釋放腰鬼, 而timer需要等self才能釋放嵌赠,如此一來塑荒,造成循環(huán)引用,相互等待釋放姜挺,最后齿税,誰也沒有釋放掉~

思考中~??,bingo??
既然dealloc中不能寫炊豪,那我在viewDidDisappear:中寫可以不凌箕,試試~

測試中~...

??看到控制臺輸出一段字母ViewController dealloc,頓時心情很是愉悅??
這樣的話词渤,這個循環(huán)引用的問題不就解決了么~牵舱,好吧,就這樣了??

too young too simple~
這樣釋放掉timer會存在一個潛在的問題缺虐,假如當前這個頁面的timer是在做一個模塊停留計時的動作

假設是這樣子的:

用戶從A進入B模塊芜壁,此時B開始計時,
用戶從B的首頁BHomeViewController進入到BSubViewController時,timer就已經停掉了
再從B返回到A時慧妄,此時的計時時間僅僅只有停留在BHomeViewController的時間

這樣的結果顷牌,肯定不是我們想要的,如果在此基礎上塞淹,想要得到一個較準確的計時時間窟蓝,我們就必須加上一些(多余的)標記代碼,來記錄需要的一些狀態(tài)饱普,想一想运挫,axb,真夠low的??

于是乎套耕,各種面向搜索引擎滑臊,還是找到了本篇文章~
如何安全而又優(yōu)雅的使用NSTimer
此處直接貼代碼,代碼不復雜箍铲,相信各位看官都看的懂

NSTimer+Secure.h

#import <Foundation/Foundation.h>

@interface NSTimer (Secure)
/// 默認 repeats
+ (instancetype _Nullable)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id _Nonnull)aTarget selector:(SEL _Nonnull)aSelector;
+ (instancetype _Nullable)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id _Nonnull)aTarget selector:(SEL _Nonnull)aSelector repeats:(BOOL)yesOrNo;

/// 默認 repeats
+ (instancetype _Nullable)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id _Nonnull)aTarget block:(void (^_Nonnull)(void))block;
+ (instancetype _Nullable)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id _Nonnull)aTarget repeats:(BOOL)yesOrNo block:(void (^_Nonnull)(void))block;
@end

NSTimer+Secure.m

#import "NSTimer+Secure.h"

@interface SeTimerTarget: NSObject
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *timer;

@property (nonatomic, copy) void(^block)(void);
@end

@implementation SeTimerTarget
- (void)seTimerTargetAction:(NSTimer *)timer {
    if (self.target) {
        IMP imp = [self.target methodForSelector:self.selector];
        void (*func)(id, SEL, NSTimer*) = (void *)imp;
        func(self.target, self.selector, timer);
    }
    else {
        [self.timer invalidate];
        self.timer = nil;
    }
}

- (void)seTimerBlockAction:(NSTimer *)timer {
    if (self.target && self.block) {
        self.block();
    }
    else {
        [self.timer invalidate];
        self.timer = nil;
    }
}

- (void)dealloc {
    NSLog(@"==== timer dealloc ====");
}
@end

@implementation NSTimer (Secure)

+ (instancetype)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector {
    return [self seScheduledTimerWithTimeInterval:ti target:aTarget selector:aSelector repeats:YES];
}

+ (instancetype)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector repeats:(BOOL)yesOrNo {
    SeTimerTarget *timerTarget = [[SeTimerTarget alloc] init];
    NSTimer *timer = [NSTimer timerWithTimeInterval:ti target:timerTarget selector:@selector(seTimerTargetAction:) userInfo:nil repeats:yesOrNo];
    timerTarget.target = aTarget;
    timerTarget.selector = aSelector;
    timerTarget.timer = timer;
    
    [[NSRunLoop mainRunLoop] addTimer:timerTarget.timer forMode:NSRunLoopCommonModes];
    return timerTarget.timer;
}

+ (instancetype)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget block:(void (^)(void))block {
    return [self seScheduledTimerWithTimeInterval:ti target:aTarget repeats:YES block:block];
}

+ (instancetype)seScheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget repeats:(BOOL)yesOrNo block:(void (^)(void))block {
    SeTimerTarget *timerTarget = [[SeTimerTarget alloc] init];
    timerTarget.block = block;
    timerTarget.target = aTarget;
    NSTimer *timer = [NSTimer timerWithTimeInterval:ti target:timerTarget selector:@selector(seTimerBlockAction:) userInfo:nil repeats:yesOrNo];
    timerTarget.timer = timer;
    
    [[NSRunLoop mainRunLoop] addTimer:timerTarget.timer forMode:NSRunLoopCommonModes];
    return timerTarget.timer;
}
@end

也可以在GitHub上去下載我的測試demo
從上面NSTimer+Secure.h中可以看出雇卷,作者提供了兩種NSTimer事件回調方式,target-actionblock

在使用中颠猴,也是很方便

 [NSTimer seScheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerAction) repeats:YES];

或者

 __weak typeof(self) weakSelf = self;
[NSTimer seScheduledTimerWithTimeInterval:0.1 target:self block:^{
    [weakSelf timerAction];
}];

這樣使用NSTimer关划,就完美解決以上所說的問題,也無需關心timerviewController誰先釋放的問題
安全而又優(yōu)雅的code??

demo地址
以上是本篇分享的所有內容翘瓮,希望對你有所幫助??~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末贮折,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子资盅,更是在濱河造成了極大的恐慌调榄,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呵扛,死亡現(xiàn)場離奇詭異每庆,居然都是意外死亡,警方通過查閱死者的電腦和手機今穿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門缤灵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蓝晒,你說我怎么就攤上這事腮出。” “怎么了芝薇?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵胚嘲,是天一觀的道長。 經常有香客問我洛二,道長馋劈,這世上最難降的妖魔是什么立倍? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮侣滩,結果婚禮上口注,老公的妹妹穿的比我還像新娘。我一直安慰自己君珠,他們只是感情好寝志,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著策添,像睡著了一般材部。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唯竹,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天乐导,我揣著相機與錄音,去河邊找鬼浸颓。 笑死物臂,一個胖子當著我的面吹牛,可吹牛的內容都是我干的产上。 我是一名探鬼主播棵磷,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晋涣!你這毒婦竟也來了仪媒?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤谢鹊,失蹤者是張志新(化名)和其女友劉穎算吩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佃扼,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡偎巢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了松嘶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艘狭。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖翠订,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情遵倦,我是刑警寧澤尽超,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站梧躺,受9級特大地震影響似谁,放射性物質發(fā)生泄漏傲绣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一巩踏、第九天 我趴在偏房一處隱蔽的房頂上張望秃诵。 院中可真熱鬧,春花似錦塞琼、人聲如沸菠净。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毅往。三九已至,卻和暖如春派近,著一層夾襖步出監(jiān)牢的瞬間攀唯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工渴丸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侯嘀,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓谱轨,卻偏偏與公主長得像残拐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碟嘴,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內容