iOS里常常會用到一些定時器的地方,這里有這么幾種方法可以使用:
NSTimer、CADisplayLink 和 GCD
一、NSTimer####
NSTimer是我們在寫iOS定時器的時候比較常用的一種,關于NSTimer有幾點需要注意的,一是內存泄露問題,二是延時問題。關于這些這些問題的解決和NSTimer的使用在NSTimer需要注意的地方中有寫。
二、CADisplayLink####
-
創建方法
@interface ViewController () @property (nonatomic) CADisplayLink *displayLink; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)]; _displayLink.frameInterval = 60; [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] 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就會被調用一次。所以通常情況下,按照iOS設備屏幕的刷新率60次/秒
延遲:iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。但如果調用的方法比較耗時,超過了屏幕刷新周期,就會導致跳過若干次回調調用機會。 如果CPU過于繁忙,無法保證屏幕60次/秒的刷新率,就會導致跳過若干次調用回調方法的機會,跳過次數取決CPU的忙碌程度。
使用場景:從原理上可以看出,CADisplayLink適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用于界面渲染。
- 重要屬性
frameInterval
NSInteger類型的值,用來設置間隔多少幀調用一次selector方法,默認值是1,即每幀都調用一次。
duration
readOnly的CFTimeInterval值,表示兩次屏幕刷新之間的時間間隔。需要注意的是,該屬性在target的selector被首次調用以后才會被賦值。selector的調用間隔時間計算方式是:調用間隔時間 = duration × frameInterval。
三、GCD####
-
創建方法
@interface ViewController () @property (nonatomic) dispatch_source_t timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; double delayInSeconds = 1.0; _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC, 0.0); dispatch_source_set_event_handler(_timer, ^{ NSLog(@"timer date 1== %@",[NSDate date]); }); dispatch_resume(_timer); }
-
停止方法
dispatch_source_cancel(self.timer); dispatch_release(self.timer); self.source = nil;