iOS中的NSTimer定時器的初步使用解析_IOS

來源:互聯網
上載者:User

建立一個定時器(NSTimer)

- (void)viewDidLoad {  [super viewDidLoad];  [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(actionTimer:) userInfo:nil repeats:YES];}- (void)actionTimer:(NSTimer *)timer{}

NSTimer預設運行在default mode下,default mode幾乎包括所有輸入源(除NSConnection) NSDefaultRunLoopMode模式。

actionTimer方法會每隔1s中被調用一次。NSTimer使用起來是不是非常簡單。這是NSTimer比較初級的應用。

當主介面被滑動時NSTimer失效了

主介面被滑動是什麼意思呢?就是說主介面有UITableView或者UIScrollView,滑動UITableView或者UIScrollView。這個時候NSTimer失效了。

我們來寫一個demo,在一個有UITableView的UIViewController上啟動定時器,每1s數字加1,並將這個數字顯示在UILabel上面.

- (void)viewDidLoad {  [super viewDidLoad];  [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(actionTimer:) userInfo:nil repeats:YES];}- (void)actionTimer:(NSTimer *)timer{  self.number++;  self.label.text = [NSString stringWithFormat:@"%d",self.number];  NSLog(@"%d",self.number);}

關於UITableView和UILabel的建立我省去了。詳細的代碼可以點擊這裡下載:iOSStrongDemo,iOSStrongDemo我會不斷更新,大家在github上star一下。

這樣當使用者在拖動UITableView處於UITrackingRunLoopMode時,NSTimer就失效了,不能fire。self.label上的數字也就無法更新。

修改NSTimer的run loop

解決方案就是將其加入到UITrackingRunLoopMode模式或NSRunLoopCommonModes模式中。

[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];

或者

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

NSRunLoopCommonModes:是一個模式集合,當綁定一個事件來源到這個模式集合的時候就相當於綁定到了集合內的每一個模式。

fire

我們先用 NSTimer 來做個簡單的計時器,每隔5秒鐘在控制台輸出 Fire 。比較想當然的做法是這樣的:

@interface DetailViewController ()@property (nonatomic, weak) NSTimer *timer;@end@implementation DetailViewController- (IBAction)fireButtonPressed:(id)sender {  _timer = [NSTimer scheduledTimerWithTimeInterval:3.0f                       target:self                      selector:@selector(timerFire:)                      userInfo:nil                       repeats:YES];  [_timer fire];}-(void)timerFire:(id)userinfo {  NSLog(@"Fire");}@end

運行之後確實在控制台每隔3秒鐘輸出一次 Fire ,然而當我們從這個介面跳轉到其他介面的時候卻發現:控制台還在源源不斷的輸出著 Fire 。看來 Timer 並沒有停止。

invalidate

既然沒有停止,那我們在 DemoViewController 的 dealloc 裡加上 invalidate 的方法:

-(void)dealloc {  [_timer invalidate];  NSLog(@"%@ dealloc", NSStringFromClass([self class]));}

再次運行,還是沒有停止。原因是 Timer 添加到 Runloop 的時候,會被 Runloop 強引用:

Note in particular that run loops maintain strong references to their timers, so you don't have to maintain your own strong reference to a timer after you have added it to a run loop.
然後 Timer 又會有一個對 Target 的強引用(也就是 self ):

Target is the object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
也就是說 NSTimer 強引用了 self ,導致 self 一直不能被釋放掉,所以也就走不到 self 的 dealloc 裡。

既然如此,那我們可以再加個 invalidate 按鈕:

- (IBAction)invalidateButtonPressed:(id)sender {  [_timer invalidate];}

嗯這樣就可以了。(在 SOF 上有人說該在 invalidate 之後執行 _timer = nil ,未能理解為什麼,如果你知道原因可以告訴我:)

在 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 在哪個線程建立就要在哪個線程停止,否則會導致資源不能被正確的釋放。看起來各種坑還不少。

dealloc

那麼問題來了:如果我就是想讓這個 NSTimer 一直輸出,直到 DemoViewController 銷毀了才停止,我該如何讓它停止呢?

  • NSTimer 被 Runloop 強引用了,如果要釋放就要調用 invalidate 方法。
  • 但是我想在 DemoViewController 的 dealloc 裡調用 invalidate 方法,但是 self 被 NSTimer 強引用了。
  • 所以我還是要釋放 NSTimer 先,然而不調用 invalidate 方法就不能釋放它。
  • 然而你不進入到 dealloc 方法裡我又不能調用 invalidate 方法。
  • 嗯…


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.