上次分享過一片關于NSTimer的知識,略有感觸,然而與NSTimer有類似功能效果的還有一個控件CADisplayLink,長話短說,下面會對CADisplayLink進行一個簡單而又系統的了解...
1: 什么是CADisplsyLink?
1)在屏幕刷新的時候使用:
CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內容畫到屏幕上的定時器類。CADisplayLink以特定模式注冊到runloop后,每當屏幕顯示內容刷新結束的時候,runloop就會向CADisplayLink指定的target發送一次指定的selector消息, CADisplayLink類對應的selector就會被調用一次。所以通常情況下,按照iOS設備屏幕的刷新率60次/秒(CADisplayLink 默認每秒運行60次,將它的frameInterval屬性設置為2,意味CADisplayLink每隔一幀運行一次,有效的使游戲邏輯每秒運行30次)。
2)延遲
iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。但如果調用的方法比較耗時,超過了屏幕刷新周期,就會導致跳過若干次回調調用機會。如果CPU過于繁忙,無法保證屏幕60次/秒的刷新率,就會導致跳過若干次調用回調方法的機會,跳過次數取決CPU的忙碌程度。
3)使用場景
CADisplayLink適合做界面的不停重繪,比如視頻播放的時候需要不停地獲取下一幀用于界面渲染。
2: 代碼分析
#import "CADisplayLinkController.h"
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface CADisplayLinkController ()
@property (nonatomic,strong) CADisplayLink* CADisplayLink;
@property (nonatomic,strong) UIButton* button;
@end
@implementation CADisplayLinkController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.button];
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (_CADisplayLink)
{
[_CADisplayLink invalidate];
_CADisplayLink = nil;
}
}
-(UIButton*) button
{
if (!_button)
{
_button = [UIButton buttonWithType:UIButtonTypeCustom];
_button.frame = CGRectMake(SCREEN_WIDTH / 2 - 100, SCREEN_HEIGHT / 2, 200, 40);
_button.backgroundColor = [UIColor redColor];
_button.layer.cornerRadius = 5;
[_button setTitle:@"點擊" forState:UIControlStateNormal];
[_button addTarget:self action:@selector(clickAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
-(CADisplayLink*) CADisplayLink
{
if (!_CADisplayLink)
{
/*創建一個_CADisplayLink對象,然后在target上綁定selector*/
_CADisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(startDisplayLink:)];
[_CADisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; /*將_CADisplayLink加入到RunLoop里面之后,selector就會被周期性的調用*/
}
return _CADisplayLink;
}
#pragma mark - 點擊button
-(void) clickAction:(UIButton*) sender
{
[self CADisplayLink];
}
#pragma mark - 開始繪制
-(void) startDisplayLink:(id) sender
{
NSLog(@"startDisplayLink");
}
#pragma mark - touch屏幕,取消相應事件
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[_CADisplayLink invalidate]; /*將CADisplayLink從RunLoop中移除,selector的調用也會停止*/
_CADisplayLink = nil; /*銷毀CADisplayLink, 這樣可以避免控制器不死*/
}
3:細節點
1) 關于暫停和開啟設置
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
_CADisplayLink.paused = NO; /*開啟, 類似于NSTimer的distantPast屬性*/
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
_CADisplayLink.paused = YES; /*暫停屬性,類似于NSTimer的distantFuture*/
}
2) 關于NSRunLoopMode
NSDefaultRunLoopModel:監聽用戶最基本的操作(點擊,觸摸等)
NSRunLoopCommonModels:監聽一些特殊操作:滾動等
那么,為什么在NSDefaultRunLoopModel模式下發生滾動,計時器會停止?那是因為系統認為,用戶不應該邊滾動邊操作界面,所以停止了(觸碰,點擊等)NSDefaultRunLoopModel模式下監聽的事件
4:CADisplayLink與NSTimer之間的差異
1)精確度
iOS設備的屏幕刷新頻率是固定的,CADisplayLink在正常情況下會在每次刷新結束都被調用,精確度相當高。NSTimer的精確度就顯得低了點,比如NSTimer的觸發時間到的時候,runloop如果在阻塞狀態,觸發時間就會推遲到下一個runloop周期。并且NSTimer新增了tolerance屬性,讓用戶可以設置可以容忍的觸發的時間的延遲范圍。
2)使用場合
CADisplayLink使用場合相對專一,適合做UI的不停重繪,比如自定義動畫引擎或者視頻播放的渲染。NSTimer的使用范圍要廣泛的多,各種需要單次或者循環定時處理的任務都可以使用,比如用在背景計算,更新一些數值資料。在UI相關的動畫或者顯示內容使用 CADisplayLink比起用NSTimer的好處就是我們不需要在格外關心屏幕的刷新頻率了,因為它本身就是跟屏幕刷新同步的。
- 上面的一些基礎知識,一些是自己在網上百度整合的,大概整理一下,關于如上的知識,幾乎看完這些,差不多能有個大差不差的理解,謝謝您的閱讀
參考知識:
NSRunLoopMode解析
NSTimer基礎
官方文檔
Core Animation系列之CADisplayLink