一坡椒,NSTimer
//創(chuàng)建方式1
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:NO];
[timer invalidate];
//調(diào)用創(chuàng)建方法后,target對象的計數(shù)器會加1尤溜,直到執(zhí)行完畢倔叼,自動減1。如果是循環(huán)執(zhí)行的話宫莱,就必須手動關閉丈攒,否則可以不執(zhí)行釋放方法。
//推薦-->創(chuàng)建方式2
NSTimer *timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer invalidate];
存在延遲:不管是一次性的還是周期性的timer的實際觸發(fā)事件的時間梢睛,都會與所加入的RunLoop和RunLoop Mode有關肥印,如果此RunLoop正在執(zhí)行一個連續(xù)性的運算,timer就會被延時出發(fā)绝葡。
二,CADisplayLink
- (void)startDisplayLink{
self.displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink{
//do something
}
- (void)stopDisplayLink{
[self.displayLink invalidate];
self.displayLink = nil;
}
CADisplayLink是一個能讓我們以和屏幕刷新率同步的頻率將特定的內(nèi)容畫到屏幕上的定時器類腹鹉。 CADisplayLink以特定模式注冊到runloop后藏畅, 每當屏幕顯示內(nèi)容刷新結(jié)束的時候,runloop就會向 CADisplayLink指定的target發(fā)送一次指定的selector消息, CADisplayLink類對應的selector就會被調(diào)用一次愉阎。
iOS設備的屏幕刷新頻率是固定的绞蹦,CADisplayLink在正常情況下會在每次刷新結(jié)束都被調(diào)用,精確度相當高榜旦。使用場合相對專一幽七,適合做UI的不停重繪,比如自定義動畫引擎或者視頻播放的渲染溅呢。不需要在格外關心屏幕的刷新頻率了澡屡,本身就是跟屏幕刷新同步的。
三咐旧,GCD
1.執(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.重復執(zhí)行
NSTimeInterval period = 1.0; //設置時間間隔
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_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒執(zhí)行
dispatch_source_set_event_handler(_timer, ^{ //在這里執(zhí)行事件 });
dispatch_resume(_timer);
GCD的定時器和NSTimer是不一樣的驶鹉,NSTimer受RunLoop影響氧秘,但是GCD的定時器不受影響坤溃,因為RunLoop也是基于GCD的
計時器(全局)
@interface ViewController ()
@property(nonatomic,strong)NSTimer *timer; // timer
@property(nonatomic,assign)int countDown; // 倒數(shù)計時用
@property(nonatomic,strong)NSDate *beforeDate; // 上次進入后臺時間
@end
static int const tick = 60;
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupNotification];
[self startCountDown];
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
[self stopTimer];
}
-(void)setupNotification {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(enterBG) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(enterFG) name:UIApplicationWillEnterForegroundNotification object:nil];
}
/**
* 進入后臺記錄當前時間
*/
-(void)enterBG {
NSLog(@"應用進入后臺啦");
_beforeDate = [NSDate date];
}
/**
* 返回前臺時更新倒計時值
*/
-(void)enterFG {
NSLog(@"應用將要進入到前臺");
NSDate * now = [NSDate date];
int interval = (int)ceil([now timeIntervalSinceDate:_beforeDate]);
int val = _countDown - interval;
if(val > 1){
_countDown -= interval;
}else{
_countDown = 1;
}
}
/**
* 開始倒計時
*/
-(void)startCountDown {
_countDown = tick; //< 重置計時
_timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES]; //< 需要加入手動RunLoop黄伊,需要注意的是在NSTimer工作期間self是被強引用的
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; //< 使用NSRunLoopCommonModes才能保證RunLoop切換模式時讲岁,NSTimer能正常工作涕蜂。
}
-(void)timerFired:(NSTimer *)timer {
if (_countDown == 0) {
[self stopTimer];
NSLog(@"重新發(fā)送");
}else{
_countDown -=1;
NSLog(@"倒計時中:%d",_countDown);
}
}
- (void)stopTimer {
if (_timer) {
[_timer invalidate];
}
}