一、NSTimer
// 方式1:底层自动把timer加入Runloop的NSDefaultRunLoopMode中
// 所以我们不需要手动将timer加入到Runloop中
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];//repeats表示循环。若为NO则
// 方式2:必须手动将timer加入到Runloop。否则定时器无法工作
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
- 方式1的详情代码
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self timer3];
}
-(void)timer3{
//1.创建定时器
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];//repeats表示循环。若为NO则只循环一次,为YES则无限循环
}
-(void)task
{
NSLog(@"task---%@--%@",[NSThread currentThread],[NSRunLoop currentRunLoop].currentMode);
}
@end
效果
- 方式2的详情代码
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self timer3];
}
-(void)timer3{
//1.创建定时器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
//2.把定时器添加到RunLoop中.
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
-(void)task
{
NSLog(@"task---%@--%@",[NSThread currentThread],[NSRunLoop currentRunLoop].currentMode);
}
@end
效果
二、GCD
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic ,strong) dispatch_source_t timer;
@end
@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
//1.创建定时器对象
/*
第一个参数:DISPATCH_SOURCE_TYPE_TIMER 创建的是一个定时器
第四个参数:队列,决定在哪个线程中执行任务.
第四个参数若为dispatch_get_main_queue(),则在主线程中执行.其余的队列都在子线程执行【已验证】
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 3.0 *NSEC_PER_SEC);
//2.设置定时器(间隔时间|开始时间)
/*
第一个参数:定时器对象
第二个参数:从什么时候开始计时 DISPATCH_TIME_NOW == 从现在开始
第三个参数:间隔时间 2.0 以纳秒为单位
第四个参数:精准度(表示允许的误差)== 0
*/
dispatch_source_set_timer(timer, t, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//3.定义定时器的工作
dispatch_source_set_event_handler(timer, ^{
NSLog(@"----GCD----%@",[NSThread currentThread]);
});
//4.启动执行
dispatch_resume(timer);
//程序执行顺序:1-->2-->3-->4-->5-->花括号(局部变量被销毁)-->2秒后执行3中的代码块-->每隔两秒一直打印3中的代码块
//timer是个局部变量,程序执行到花括号的地方,timer就被销毁了,而3中的代码块的内容真正被执行的时间是执行到花括号的时候再加上2秒才执行,此时timer早就被销毁了。所以必须用一个强指针引用着timer。保证即使出了花括号,timer这个变量仍然存在。
//self.timer是由外界的ispatch_source_t timer强引用着(strong类型的修饰符),通过self.timer=timer就保证了timer也由外界的强指针强引用着.
//若换成weak,就不行了,出因为了花括号,无论是timer还是self.timer都会被销毁.
self.timer = timer;//5
}
@end
效果
三、CADisplayLink
参考链接1
参考链接2
参考链接3
CADisplayLink是一个能让我们以和屏幕刷新率同步的频率将特定的内容画到屏幕上的定时器类。 CADisplayLink以特定模式注册到runloop后, 每当屏幕显示内容刷新结束的时候,runloop就会向 CADisplayLink指定的target发送一次指定的selector消息, CADisplayLink类对应的selector就会被调用一次。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self timer3];
}
-(void)timer3{
CADisplayLink* gameTimer;
gameTimer = [CADisplayLink displayLinkWithTarget:self
selector:@selector(task)];
[gameTimer addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
-(void)task
{
NSLog(@"task---%@--%@",[NSThread currentThread],[NSRunLoop currentRunLoop].currentMode);
}
@end
效果