iOS中的三大定時器 iOS開發中定時器經常會用到,iOS中常用的定時器有三種,分別是NSTime,CADisplayLink和GCD。
iOS開發中定時器經常會用到,iOS中常用的定時器有三種,分別是NSTime,CADisplayLink和GCD。
NSTimer
方式1
// 建立定時器
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(test) userInfo:nil repeats:YES];
// 停止定時器
[timer invalidate];
方式2
// 建立定時器
NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(test) userInfo:nil repeats:YES];
// 將定時器新增到runloop中,否則定時器不會啟動
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 停止定時器
[timer invalidate];
方式1會自動將建立的定時器以預設方式新增到當前執行緒runloop中,而無需手動新增。但是在此種模式下,當滾動螢幕時runloop會進入另外一種模式,定時器會暫停,為了解決這種問題,可以像方式2那樣把定時器新增到NSRunLoopCommonModes模式下。
方式1和方式2在設定後都會在間隔設定的時間(本例中設定為2s)後執行test方法,如果需要立即執行可以使用下面的程式碼。
[time fire];
CADisplayLink
// 建立displayLink
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(test:)];
// 將建立的displaylink新增到runloop中,否則定時器不會執行
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// 停止定時器
[displayLink invalidate];
displayLink = nil;
當把CADisplayLink物件add到runloop中後,selector就能被週期性呼叫,類似於重複的NSTimer被啟動了;執行invalidate操作時,CADisplayLink物件就會從runloop中移除,selector呼叫也隨即停止,類似於NSTimer的invalidate方法
呼叫時機
CADisplayLink是一個和螢幕重新整理率同步的定時器類。CADisplayLink以特定模式註冊到runloop後,每當螢幕顯示內容重新整理結束的時候,runloop就會向CADisplayLink指定的target傳送一次指定的selector訊息,CADisplayLink類對應的selector就會被呼叫一次,所以可以使用CADisplayLink做一些和螢幕操作相關的操作。
重要屬性
-
frameInterval
NSInteger型別的值,用來設定間隔多少幀呼叫一次selector方法,預設值是1,即每幀都呼叫一次。
-
duration
readOnly的CFTimeInterval值,表示兩次螢幕重新整理之間的時間間隔。需要注意的是,該屬性在target的selector被首次呼叫以後才會被賦值。selector的呼叫間隔時間計算方式是:呼叫間隔時間 = duration × frameInterval。
GCD定時器
一次性定時
dispatch_time_t timer = dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC);
dispatch_after(timer, dispatch_get_main_queue(), ^(void){
NSLog(@"GCD-----%@",[NSThread currentThread]);
});
重複執行的定時器
@property (nonatomic ,strong)dispatch_source_t timer;// 注意:此處應該使用強引用 strong
{
//0.建立佇列
dispatch_queue_t queue = dispatch_get_main_queue();
//1.建立GCD中的定時器
/*
第一個引數:建立source的型別 DISPATCH_SOURCE_TYPE_TIMER:定時器
第二個引數:0
第三個引數:0
第四個引數:佇列
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
//2.設定時間等
/*
第一個引數:定時器物件
第二個引數:DISPATCH_TIME_NOW 表示從現在開始計時
第三個引數:間隔時間 GCD裡面的時間最小單位為 納秒
第四個引數:精準度(表示允許的誤差,0表示絕對精準)
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//3.要呼叫的任務
dispatch_source_set_event_handler(timer, ^{
NSLog(@"GCD-----%@",[NSThread currentThread]);
});
//4.開始執行
dispatch_resume(timer);
//
self.timer = timer;
}
此處注意一定要強引用定時器
,否則定時器執行到 } 後將會被釋放,無定時效果。
GCD定時器時間非常精準,最小的定時時間可以達到1納秒,所以用在非常精確的定時場合。
GCD定時器
-
GCD定時器不受RunLoop約束,比NSTimer更加準時
-
證明,實現GCD定時器
<code class="objectivec" style="padding: 0px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border: none; background-color: transparent;"><span class="hljs-class"><span class="hljs-keyword" style="color: rgb(133, 153, 0);">@interface</span> <span class="hljs-title" style="color: rgb(181, 137, 0);">ViewController</span> ()</span> <span class="hljs-comment" style="color: rgb(147, 161, 161);">/** 定時器(這裡不用帶*,因為dispatch_source_t就是個類,內部已經包含了*) */</span> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">@property</span> (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">nonatomic</span>, <span class="hljs-keyword" style="color: rgb(133, 153, 0);">strong</span>) dispatch_source_t timer; <span class="hljs-keyword" style="color: rgb(133, 153, 0);">@end</span></code>
<code class="cpp" style="padding: 0px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; border: none; background-color: transparent;"> <span class="hljs-keyword" style="color: rgb(133, 153, 0);">int</span> count = <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>;
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 獲得佇列</span>
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">dispatch_queue_t</span> <span class="hljs-built_in" style="color: rgb(38, 139, 210);">queue</span> = dispatch_get_main_queue();
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 建立一個定時器(dispatch_source_t本質還是個OC物件)</span>
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>, <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>, <span class="hljs-built_in" style="color: rgb(38, 139, 210);">queue</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 設定定時器的各種屬性(幾時開始任務,每隔多長時間執行一次)</span>
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// GCD的時間引數,一般是納秒(1秒 == 10的9次方納秒)</span>
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 何時開始執行第一個任務</span>
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比當前時間晚3秒</span>
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">dispatch_time_t</span> start = dispatch_time(DISPATCH_TIME_NOW, (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">int64_t</span>)(<span class="hljs-number" style="color: rgb(42, 161, 152);">1.0</span> * NSEC_PER_SEC));
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">uint64_t</span> interval = (<span class="hljs-keyword" style="color: rgb(133, 153, 0);">uint64_t</span>)(<span class="hljs-number" style="color: rgb(42, 161, 152);">1.0</span> * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, <span class="hljs-number" style="color: rgb(42, 161, 152);">0</span>);
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 設定回撥</span>
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@<span class="hljs-string" style="color: rgb(42, 161, 152);">"------------%@"</span>, [NSThread currentThread]);
count++;
<span class="hljs-keyword" style="color: rgb(133, 153, 0);">if</span> (count == <span class="hljs-number" style="color: rgb(42, 161, 152);">4</span>) {
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 取消定時器</span>
dispatch_cancel(self.timer);
self.timer = nil;
}
});
<span class="hljs-comment" style="color: rgb(147, 161, 161);">// 啟動定時器</span>
dispatch_resume(self.timer);</code>