iOS之 NSTimer(一)
以前沒怎么了解過這個NSTimer,其實還是有挺多坑的,今天來總結(jié)一下:
首先我們一起來看這個:
我在A ?-> (push) -> B控制器,然后再B控制器中開啟了一個NSTimer。然后我又pop到A
?
pop到A的時候,定時器還在運行,并且B沒有被釋放(未調(diào)用dealloc)。why?
這就不得不讓我聯(lián)想到我上篇寫到的 “常駐線程”了,莫非NSTimer也是添加到了RunLoop?
這說明本例中的NSTimer確實是跑在了NSRunLoop中。
那為什么B沒有釋放呢?
Timer對Target進(jìn)行了強引用。timer沒有被釋放,那么B就不會被釋放了。也就走不到Dealloc了。那么我們就得在B離開的時候,要對timer進(jìn)行invalidate。
- (void)viewWillDisappear:(BOOL)animated{[super viewWillDisappear:animated];[_timer invalidate]; }?
?這個時候NSTimer 銷毀了。pop到A的時候,有調(diào)用B的dealloc。
?
================ NSTimer 與 RunLoop 的關(guān)系
1.什么是NSTimer?
??A timer waits until a certain time interval has elapsed and then fires, sending a specified message to a target object.
timer是一個能從某時刻或者周期性的給target對象發(fā)送一條指定的消息。
定時器是線程通知自己做某件事的方法,定時器和你的RunLoop的特定的模式相關(guān)。如果定時器所在的模式當(dāng)前未被RunLoop監(jiān)視,那么定時器將不會開始 直到RunLoop運行在相應(yīng)的模式下。如果RunLoop不在運行,那定時器也將永遠(yuǎn)不啟動。
?
?
2. NSTimer的生命周期:
You specify whether a timer is repeating or non-repeating at creation time. A non-repeating timer fires once and then invalidates itself automatically, thereby preventing the timer from firing again. By contrast, a repeating timer fires and then reschedules itself on the same run loop.
A repeating timer always schedules itself based on the scheduled firing time, as opposed to the actual firing time
NSTimer 會對外界傳遞的target進(jìn)行retain。如果是一次性調(diào)用(repeats:NO),會在本次調(diào)用之后自身invalidate,并且NSTimer retain的那個target會做一次release。
但是,如果是多次重復(fù)調(diào)用,就需要我們自己手動進(jìn)行invalidate,不然NSTimer一直存在。
?
invalidate的方法中有這么一段話:
You must send this message from the thread on which the timer was installed. If you send this message from another thread, the input source associated with the timer may not be removed from its run loop, which could prevent the thread from exiting properly.NSTimer在那個線程創(chuàng)建就要在那個線程停止,否則資源不能正確的釋放。
?
?
?
3. NSTimer的Tolerance(容差),不是實時機制
無論是單次執(zhí)行的NSTimer還是重復(fù)執(zhí)行的NSTimer都不是準(zhǔn)時的,這與當(dāng)前NSTimer所處的線程有很大的關(guān)系,如果NSTimer當(dāng)前所處的線程正在進(jìn)行大數(shù)據(jù)處理(假設(shè)為一個大循環(huán)),NSTimer本次執(zhí)行會等到這個大數(shù)據(jù)處理完畢之后才會繼續(xù)執(zhí)行。
這期間有可能會錯過很多次NSTimer的循環(huán)周期,但是NSTimer并不會將前面錯過的執(zhí)行次數(shù)在后面都執(zhí)行一遍,而是繼續(xù)執(zhí)行后面的循環(huán),也就是在一個循環(huán)周期內(nèi)只會執(zhí)行一次循環(huán)。
無論循環(huán)延遲的多離譜,循環(huán)間隔都不會發(fā)生變化,在進(jìn)行完大數(shù)據(jù)處理之后,有可能會立即執(zhí)行一次NSTimer循環(huán),但是后面的循環(huán)間隔始終和第一次添加循環(huán)時的間隔相同。
?
重復(fù)工作定時器會基于安排好的時 間而非實際時間調(diào)度它自己運行。舉個例子,如果定時器被設(shè)定在某一特定時間開始 并 5 秒重復(fù)一次,那么定時器會在那個特定時間后 5 秒啟動,即使在那個特定的觸發(fā) 時間延遲了。如果定時器被延遲以至于它錯過了一個或多個觸發(fā)時間,那么定時器會 在下一個最近的觸發(fā)事件啟動,而后面會按照觸發(fā)間隔正常執(zhí)行?
?
4.Timers work in conjunction with run loops
其實上面的例子中我們使用的是“?create the timer and schedule it ?on the current run loop in the default mode”。這個是在主線程中,所以Runloop是開啟的,不需要我們手動打開。
- ? 上面的Source/Timer/Observer被統(tǒng)稱為mode item,一個item可以被同時加入多個mode。但一個item被重復(fù)加入同一個mode時是不會有效果的。如果一個mode中一個item都沒有,則RunLoop會被直接退出,不進(jìn)入循環(huán)。
- 一個RunLoop包含若干個Mode,每個Mode又包含活干個Source/Timer/Oberver,每次調(diào)用RunLoop的主函數(shù),只能指定其中的一個Mode,?這個Mode被稱作CurrentMode。如果需要切換Mode,只能退出Loop,再重新指定一個Mode進(jìn)入。這樣做的目的: 為了分隔不同組的Source/Timeer/Oberver,讓其互不影響.
- 在iOS多線程中,每一個線程都有一個Runloop,但是只有主線程的Runloop默認(rèn)是打開的,其他子線程也就是我們創(chuàng)建的線程的Runloop默認(rèn)是關(guān)閉的,需要我們手動運行。我們可以通過[NSRunLoop currentRunLoop]來獲得當(dāng)前線程的Runloop,并且調(diào)用[runloop addTimer:timer forMode:NSDefaultRunLoopMode]方法將定時器添加到runloop中,最后一定不要忘記調(diào)用runloop的run方法將當(dāng)前runloop開啟,否則NSTimer永遠(yuǎn)也不會運行。
?
NSTimer可以創(chuàng)建一個定時源。
NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop]; NSDate *futureDate = [NSDate dateWithTimeIntervalSinceNow:1.0];_timer = [[NSTimer alloc] initWithFireDate:futureDate interval:1 target:self selector:@selector(doSomething) userInfo:nil repeats:YES];[myRunLoop addTimer:_timer forMode:NSDefaultRunLoopMode];?
?5.對于UIScrollView的Timer
當(dāng)使用NSTimer的scheduledTimerWithTimeInterval方法時。事實上此時Timer會被加入到當(dāng)前線程的Run Loop中,且模式是默認(rèn)的NSDefaultRunLoopMode。而如果當(dāng)前線程就是主線程,也就是UI線程時,某些UI事件,比如UIScrollView的拖動操作,會將Run Loop切換成NSEventTrackingRunLoopMode模式,在這個過程中,默認(rèn)的NSDefaultRunLoopMode模式中注冊的事件是不會被執(zhí)行的。也就是說,此時使用scheduledTimerWithTimeInterval添加到RunLoop中的Timer就不會執(zhí)行。
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback) userInfo:nil repeats:YES];//使用NSRunLoopCommonModes模式,把timer加入到當(dāng)前Run Loop中。[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];?
?
?
?
?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/Ohero/p/4828623.html
總結(jié)
以上是生活随笔為你收集整理的iOS之 NSTimer(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中的is
- 下一篇: Toast的基本用法 吐司打印