定時器
NSTimer
- 1.創(chuàng)建方式:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInteral:1.0 target:self selector:@selector(action:) userInfo:ni] repeat:NO];
- TimerIntval:執(zhí)行之前等待的時間.比如設(shè)置成1.0 就代表1秒后執(zhí)行
- target:需要執(zhí)行方法的對象;
- selector:需要執(zhí)行的方法;
- repeats:是否需要循環(huán);
- 2.釋放方法:
[timer invalidate];
注意:調(diào)用創(chuàng)建方法后,target對象的引用計數(shù)會+1,直到執(zhí)行完畢,自動-1.如果循環(huán)執(zhí)行的話必須手動關(guān)閉.否則可以不執(zhí)行釋放方法;
3.特性:
存在延遲:不管是一次性還是周期性的timer的實際觸發(fā)事件的時間,都會與所加入的RunLoop和RunLoopMode有關(guān).如果RunLoop正在執(zhí)行一個連續(xù)的運(yùn)算,timer就會被延遲觸發(fā).重復(fù)性的timer遇到這種情況,如果延遲超過一個周期,則會和后面的觸發(fā)進(jìn)行合并,即在一個周期內(nèi)只會觸發(fā)一次。但是不管該timer的觸發(fā)時間延遲的有多離譜,他后面的timer的觸發(fā)時間總是倍數(shù)于第一次添加timer的間隙。
必須加入RunLoop::使用上面的創(chuàng)建方式,會自動把timer加入MainRunloop的NSDefaultRunLoopMode中.如果使用以下方式創(chuàng)建定時器,就必須手動加入Runloop:
NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self seletor:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunloop mainRunloop] addTimer:timer forMode:NSDefaultRunloopMode];
CADisplayLink
- 1.創(chuàng)建方法
self.displayLink = [CADisplayLink displayLinkWithTarget:self sel:ector:@selector(handleDisplaylink:)];
[self.displayLink addToRunLoop:[NSRunLoop curentRunLoop] forMode:NSDefaultRunLoopMode];
- 2.停止方法:
[self.displayLink invailidate];
self.displayLink = nil;
注:**當(dāng)把CADisplayLink對象add到runloop中后,selector就能被周期性調(diào)用,類似于重復(fù)的NSTimer被啟動了;執(zhí)行invalidate操作時,CADisplayLink對象就會從runloop中移除,selector調(diào)用也隨即停止,類似于NSTimer的invalidate方法。
- 3.特性:
- 屏幕刷新時調(diào)用
- CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內(nèi)容畫到屏幕上的定時器類。CADisplayLink以特定模式注冊到runloop后,每當(dāng)屏幕顯示內(nèi)容刷新結(jié)束的時候,runloop就會向CADisplayLink指定的target發(fā)送一次指定的selector消息, CADisplayLink類對應(yīng)的selector就會被調(diào)用一次。所以通常情況下,按照iOS設(shè)備屏幕的刷新率60次/秒
- 延遲:
- OS設(shè)備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結(jié)束都被調(diào)用,精確度相當(dāng)高。但如果調(diào)用的方法比較耗時,超過了屏幕刷新周期,就會導(dǎo)致跳過若干次回調(diào)調(diào)用機(jī)會
- 如果CPU過于繁忙,無法保證屏幕60次/秒的刷新率,就會導(dǎo)致跳過若干次調(diào)用回調(diào)方法的機(jī)會,跳過次數(shù)取決CPU的忙碌程度。
- 使用場景:
- 從原理上可以看出,CADisplayLink適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用于界面渲染。
- 4.重要屬性
- frameInterval
NSInteger類型的值,用來設(shè)置間隔多少幀調(diào)用一次selector方法,默認(rèn)值是1,即每幀都調(diào)用一次。
duration - readOnly的CFTimeInterval值,表示兩次屏幕刷新之間的時間間隔。需要注意的是,該屬性在target的selector被首次調(diào)用以后才會被賦值。selector的調(diào)用間隔時間計算方式是:調(diào)用間隔時間 = duration × frameInterval。
GCD方式
GCD定時器不受RunLoop約束,比NSTimer更加準(zhǔn)時.
- 1.執(zhí)行一次的操作:
執(zhí)行一次
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//執(zhí)行事件
});
- 2.重復(fù)執(zhí)行的操作:
//證明,實現(xiàn)GCD定時器
@interface ViewController ()
/** 定時器(這里不用帶*,因為dispatch_source_t就是個類,內(nèi)部已經(jīng)包含了*) */
@property (nonatomic, strong) dispatch_source_t timer;
@end
int count = 0;
// 獲得隊列
dispatch_queue_t queue = dispatch_get_main_queue();
// 創(chuàng)建一個定時器(dispatch_source_t本質(zhì)還是個OC對象)
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 設(shè)置定時器的各種屬性(幾時開始任務(wù),每隔多長時間執(zhí)行一次)
// GCD的時間參數(shù),一般是納秒(1秒 == 10的9次方納秒)
// 何時開始執(zhí)行第一個任務(wù)
// dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比當(dāng)前時間晚3秒
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
dispatch_source_set_timer(self.timer, start, interval, 0);
// 設(shè)置回調(diào)
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"------------%@", [NSThread currentThread]);
count++;
if (count == 4) {
// 取消定時器
dispatch_cancel(self.timer);
self.timer = nil;
}
});
// 啟動定時器
dispatch_resume(self.timer);