1. 程式人生 > >【iOS沉思錄】iOS中如何觸發定時任務或延時任務?

【iOS沉思錄】iOS中如何觸發定時任務或延時任務?

iOS中如何觸發定時任務或延時任務?

定時任務指的是週期性的呼叫某個方法,實現任務的反覆執行,例如倒計時功能的實現;延時任務指的是等待一定時間後再執行某個任務,例如頁面的延時跳轉等。iOS中控制任務的延時或定時執行的方法有很多,使用中要注意是同步還是非同步,是否會阻塞主執行緒等問題。實現方法主要如下:

1.performSelector實現延時任務

延時任務可以通過當前UIViewController的performSelector隱式建立子執行緒實現,不會阻塞主執行緒:

/* 延遲10s執行任務 */
[self performSelector:@selector(task) withObject:nil
afterDelay:10]; -(void)task { // delay task }

2.利用sleep實現後面任務的等待,慎用,會阻塞主執行緒

NSThread sleepForTimeInterval:10.0];

3.GCD實現延時或定時任務

通過GCD實現block程式碼塊的延時執行:

dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC); 
dispatch_after(delay, dispatch_get_main_queue(), ^{
      // delay task
});

GCD也可以用來定義計時器實現定時器功能,可以設定延時開啟計時器,使用中要注意一定要定義強指標指向計時器物件才可讓計時器生效:

/* 必須要用強指標指引計時器才會生效 */
@property (nonatomic, strong)dispatch_source_t timer;

/* 在指定執行緒上定義計時器 */
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0
, 0, queue); /* 開始的時間 */ dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)); /* 設定計時器 */ dispatch_source_set_timer(_timer, when, 1.0 * NSEC_PER_SEC, 0); /* 計時器回撥block */ dispatch_source_set_event_handler(_timer, ^{ NSLog(@"dispatch_source_set_timer is working!"); }); /* 開啟計時器 */ dispatch_resume(_timer); /* 強引用計時器物件 */ self.timer = _timer;

4.NSTimer實現定時任務

5.CADisplayLink實現定時任務

CADisplayLink實現的定時器與螢幕重新整理頻率繫結在一起,是一種幀率重新整理,適用於介面的不斷重繪(例如流暢動畫和視訊播放等)。CADisplayLink以特定模式註冊到runloop後,每當螢幕顯示內容重新整理結束就會向CADisplayLink指定的target傳送一次訊息,實現target的每幀呼叫。根據需求也可以設定每幾幀呼叫一次,預設每幀都呼叫。另外通過CADisplayLink還可以獲取幀率和時間等資訊。

CADisplayLink實現方法的每幀呼叫使其計時精度非常高,但如果呼叫的方法十分耗時,超過一幀的時間間隔,會導致跳幀,跳幀次數取決於CPU的忙碌程度。

- (void)viewDidLoad {
    [super viewDidLoad];   

    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLink_SEL)];
    /* 新增到當前執行的RunLoop中啟動 */
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    /* 暫停、繼續對selector的呼叫 */
    //[displayLink setPaused:YES];
    //[displayLink setPaused:NO];
    /* 設定每幾幀呼叫一次selector,預設為1 */
    //[displayLink setPreferredFramesPerSecond:2];
    /* 移除,不再使用 */
    //[displayLink invalidate];
    //displayLink = nil;
}

- (void) displayLink_SEL{
    NSLog(@"displayLink is working!");
}

列印結果如下,每一幀都呼叫selector:

2018-02-01 11:48:02.707283+0800 IOSDemo[42328:4522489] displayLink is working!
2018-02-01 11:48:02.724375+0800 IOSDemo[42328:4522489] displayLink is working!
2018-02-01 11:48:02.742995+0800 IOSDemo[42328:4522489] displayLink is working!