iOS定時器平時用的比較多,原理比較簡單,但是真正用對卻不是哪么簡單。本篇就目前比較常用的定時器以及使用過程中需要注意的問題講解一下,如有不對的地方,歡迎指正
第一類定時器 NSTimer
- 創建一個NSTimer對象
1.主要分為兩類,一類是需要單獨加到runloop中的,另一類是不需要單獨加到runloop中的。我們可以到NSTimer的頭文件中去查看。需要做添加到runloop中的初始化方法有三個:
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;
不需要加到runloop中的初始化方法有兩個,默認添加到當前線程所在的runloop中
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- 如何讓一個定時器開始工作
1.初始化完成之后,不做任何干預,哪么定時器會在ti秒之后執行。
2.如果想讓定時器在初始化完成之后立刻執行,可以調用NSTimer的fire方法。
3.如果想讓定時器暫停,并且在另外一個時間開啟,可以按照下面的方式
[self.timer setFireDate:[NSDate distantFuture]]; //暫停一個正在執行中的Timer
[self.timer setFireDate:[NSDate distantPast]]; //開始執行一個執行中的Timer
-
第一個坑 循環引用
借用一個圖來表示一下
Paste_Image.png
千萬不要試圖在OneViewController的dealloc方法中釋放掉Timer,因為如果這種循環引用不被打破,OneViewController將永遠都不會被釋放,也就不會走dealloc方法。
- 解決的方法有兩種
1.在ViewWillDisAppear中做釋放Timer操作
2.在業務需要停掉Timer的時候 做Timer的釋放操作
3.打破這種循環引用,也就是讓timer的target不要設為self,而是設置為另外一個類,這樣就可以在controller被銷毀的時候 正確的釋放掉Timer。 - 釋放Timer的正確姿勢是:
[self.timer invalidate];
self.timer = nil;
-
第二個坑 計時不準
如果在Timer所在的線程正在做比較耗時的操作,哪么很可能會導致Timer計時不準,解決的方法也比較簡單,可以使用GCD Timer,單獨開一個線程做計時操作。
Paste_Image.png 第三個坑,Timer失效
這個坑比較簡單了,如果將Timer加到NSDefaultRunLoopMode模式下,哪么當scrollView滾動的時候,會導致Timer失效。解決方法比較簡單,就是將Timer加到NSRunLoopCommonModes模式下,這樣就確保了Timer不會失效