iOS定時器-- NSTimer?和CADisplaylink
?
一、iOS中有兩種不同的定時器:
1. ?NSTimer(時間間隔可以任意設定,最小0.1ms)//?If?seconds?is less than or equal to?0.0, this method chooses the nonnegative value of 0.1 milliseconds instead.
2. ?CADisplayLink(時間間隔不能設置,與顯示器刷新頻率一直)
二、創建和啟動定時器的3種方式:
// 方式1
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(nextImage) userInfo:nil repeats:YES]; //會自動加入當前的runloop消息循環中,不用手寫[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 方式2
// 創建 NSTimer 對象
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test1) userInfo:nil repeats:YES];
//將剛創建的 NSTimer 對象加到消息循環中, 這樣就會自動啟動定時器
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
// 方式3
// 創建計時器對象
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test1) userInfo:nil repeats:YES]
// 每次調用一次 fire 執行一次 test1方法
[timer fire]; // 執行一次 test 方法
[timer fire]; // 執行一次 test 方法
[timer fire]; // 執行一次 test 方法
[timer fire]; // 執行一次 test 方法
?
三、關于NSRunLoop相關知識:
先看看NSTimer的兩個常用方法:
+ (NSTimer?*)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;?//生成timer但不執行
+ (NSTimer?*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;?//生成timer并且納入當前線程的run loop來執行
?
NSRunLoop與timer有關方法為:
- (void)addTimer:(NSTimer?*)timer forMode:(NSString?*)mode;?//在run loop上注冊timer
?
理解run loop后,才能徹底理解NSTimer的實現原理,也就是說NSTimer實際上依賴run loop實現的。
主線程已經有run loop,所以NSTimer一般在主線程上運行都不必再調用addTimer: 。
但在非主線程上運行必須配置run loop,NSTimer在非主線程的main方法中使用,示例代碼如下:
- (void)main
{
NSTimer *myTimer =?[NSTimer scheduledTimerWithTimeInterval:1.0?target:self?selector:@selector(timer:)?userInfo:nil?repeats:YES];
NSRunLoop *runLoop =?[NSRunLoop?currentRunLoop];
[runLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; //實際上這步是不需要,scheduledTimerWithTimeInterval已經納入當前線程運行。如果使用timerWithTimeInterval則需要
while (xxx條件)
[runLoop run];
}
實際上這個線程無法退出,因為有timer事件需要處理,[runLoop run]會一直無法返回。解決辦法就是設置一個截止時間:
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]];?//每隔10秒檢查下線程循環條件,當然時間值可以根據實際情況來定。
?
特別注意:
我們通常在主線程中使用NSTimer,有個實際遇到的問題需要注意。當滑動界面時,系統為了更好地處理UI事件和滾動顯示,主線程runloop會暫時停止處理一些其它事件,這時主線程中運行的NSTimer就會被暫停。解決辦法就是改變NSTimer運行的mode(mode可以看成事件類型),不使用缺省的NSDefaultRunLoopMode,而是改用NSRunLoopCommonModes,這樣主線程就會繼續處理NSTimer事件了。具體代碼如下:
NSTimer *timer =?[NSTimer?timerWithTimeInterval:1.0?target:self?selector:@selector(timer:)?userInfo:nil?repeats:YES];
[[NSRunLoop?currentRunLoop]?addTimer:timer?forMode:NSRunLoopCommonModes];
?
ios開發經常用到的延遲調用的方法,其實就是在當前線程的run loop上注冊timer來實現定時運行的。所以如果是在非主線程上使用,一定要有一個run loop。
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray?*)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
?
四、關于CADisplaylink相關知識
注意:
嚴格意義上講 CADisplayLink 并不是計時器控件, 它是與顯示器刷新頻率一致的。比如顯示的刷新頻率是60赫茲, 那么 CADisplayLink 就會每秒鐘執行60次。正是因為這個原因所以有時也把 CADisplayLink 當做計時器控件來使用。CADisplayLink:每次屏幕刷新的時候就會調用,屏幕一般一秒刷新60次。
//CADisplayLink應用舉例
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timerAction)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];??//?添加主運行循環
- (void)timerAction
{?// 注意:這個方法并不會馬上調用drawRect,其實這個方法只是給當前控件添加刷新的標記,等下一次屏幕刷新的時候才會調用drawRect
? ? [self setNeedsDisplay];
}
//如果想把一些文字/圖片等繪制在自定義的WZView上,必須在drawRect里寫代碼
- (void)drawRect:(CGRect)rect {
? ? // 如果以后想繪制東西到view上面,必須在drawRect方法里面,不管有沒有手動獲取到上下文
? ? UIImage *image =? [UIImage imageNamed:@"雪花"];
? ? [image drawAtPoint:CGPointMake(50, _snowY)];
}
?
五、NSTimer 和CADisplaylink的區別:
1.?如果在繪圖的時候需要用到定時器,通常CADisplaylink,?NSTimer很少用于繪圖,因為調度優先級比較低,并不會準時調用。
2. 使用繪圖產生動畫時,一般用CADisplaylink定時器在@selector(timerAction:)方法里調用[self?setNeedsDisplay];方法,因為CADisplaylink是在屏幕刷新時調用一次timerAction:方法,而setNeedsDisplay方法也是在屏幕刷新時調用drawRect方法重繪圖形,二者剛好同步。這樣產生的動畫就非常流暢,不會有卡頓的感覺。
?
?
文章系作者原創,轉載請注明出處:http://www.cnblogs.com/stevenwuzheng/p/5213908.html
如有錯誤,歡迎隨時指正!
?
?
?
?