目录
一,NSTimer
二,CADisplayLink
三,dispatch_source_timer
一,NSTimer
1,基本使用
timerWithTimeInterval:
- (void)viewDidLoad {
[super viewDidLoad];
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
repeats:YES
block:^(NSTimer * _Nonnull timer) {
NSLog(@"timer running");
}];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
}
// 打印
07:21:30.266493+0800 Demo[10449:9624199] timer running
07:21:31.266367+0800 Demo[10449:9624199] timer running
07:21:32.266795+0800 Demo[10449:9624199] timer running
scheduledTimerWithTimeInterval:
- (void)viewDidLoad {
[super viewDidLoad];
// 自动添加到runloop的NSDefaultRunLoopMode中
[NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES
block:^(NSTimer * _Nonnull timer) {
NSLog(@"timer running");
}];
}
// 打印
07:24:10.249589+0800 Demo[10584:9626453] timer running
07:24:11.250144+0800 Demo[10584:9626453] timer running
07:24:12.250318+0800 Demo[10584:9626453] timer running
initWithFireDate:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"begin");
NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0]
interval:1.0
repeats:YES
block:^(NSTimer * _Nonnull timer) {
NSLog(@"timer running");
}];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
}
// 打印
07:32:16.943407+0800 Demo[10738:9632602] begin
07:32:19.944573+0800 Demo[10738:9632602] timer running
07:32:20.944960+0800 Demo[10738:9632602] timer running
07:32:21.944652+0800 Demo[10738:9632602] timer running
2,解决循环引用
/**
self强引用timer,timer强引用proxy,proxy弱引用self
*/
// YJProxy.h
@interface YJProxy : NSObject
+ (instancetype)proxyWithTarget:(id)target;
@end
// YJProxy.m
@interface YJProxy ()
@property (nonatomic, weak) id target; // 弱引用
@end
@implementation YJProxy
+ (instancetype)proxyWithTarget:(id)target {
YJProxy *proxy = [[YJProxy alloc] init];
proxy.target = target;
return proxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector { // 消息转发
return self.target;
}
@end
// ViewController
@interface ViewController ()
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:[YJProxy proxyWithTarget:self]
selector:@selector(timerTask)
userInfo:nil
repeats:YES];
}
- (void)timerTask {
NSLog(@"%s", __func__);
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self.timer invalidate];
}
@end
// 打印
07:56:14.897620+0800 Demo[11187:9646035] -[ViewController timerTask]
07:56:15.897446+0800 Demo[11187:9646035] -[ViewController timerTask]
07:56:16.898022+0800 Demo[11187:9646035] -[ViewController timerTask]
07:56:17.860300+0800 Demo[11187:9646035] -[ViewController dealloc]
3,NSProxy
- 使用
@interface YJProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@end
@interface YJProxy ()
@property (nonatomic, weak) id target;
@end
@implementation YJProxy
+ (instancetype)proxyWithTarget:(id)target {
// NSProxy没有init方法
YJProxy *proxy = [YJProxy alloc];
proxy.target = target;
return proxy;
}
// 消息转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
@end
- 说明
1>它跟
NSObject
是同一级别的2>它专用于消息转发
3>用它做代理对象效率更高,因为它是直接执行消息转发的,而
NSObject
需要先执行消息发送和动态方法解析
二,CADisplayLink
1,使用
@interface ViewController ()
@property (nonatomic, strong) CADisplayLink *link;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.link = [CADisplayLink displayLinkWithTarget:[YJProxy proxyWithTarget:self]
selector:@selector(linkTask)];
// 设置每秒执行1次
self.link.preferredFramesPerSecond = 1;
[self.link addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
- (void)linkTask {
NSLog(@"%s", __func__);
// 下一次执行的时间 - 当前时间
NSLog(@"%f", self.link.targetTimestamp - self.link.timestamp);
// 两帧之间的时间间隔
NSLog(@"%f", self.link.duration);
}
- (void)dealloc {
NSLog(@"%s", __func__);
[self.link invalidate];
}
@end
// 打印
13:26:37.176374+0800 Demo[15813:9765865] -[ViewController linkTask]
13:26:37.176581+0800 Demo[15813:9765865] 1.000000
13:26:37.176682+0800 Demo[15813:9765865] 0.016667
13:26:38.172891+0800 Demo[15813:9765865] -[ViewController linkTask]
13:26:38.173096+0800 Demo[15813:9765865] 1.000000
13:26:38.173237+0800 Demo[15813:9765865] 0.016667
13:26:39.173083+0800 Demo[15813:9765865] -[ViewController linkTask]
13:26:39.173282+0800 Demo[15813:9765865] 1.000000
13:26:39.173442+0800 Demo[15813:9765865] 0.016667
13:26:39.207185+0800 Demo[15813:9765865] -[ViewController dealloc]
2,说明
-
它是一个与屏幕刷新相关的定时器
-
屏幕刷新频率是60
FPS
,所以它默认每秒执行60次 -
duration
是按照60FPS
来计算的(1 / 60 = 0.016667)
三,dispatch_source_timer
1,使用
@interface ViewController ()
@property (nonatomic, strong) dispatch_source_t timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 创建定时器并设置执行任务的队列
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 每1秒执行一次任务并允许有1秒的误差
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 1.0 * NSEC_PER_SEC);
// 定时器任务
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"timer running---%@", [NSThread currentThread]);
});
// 定时器被取消的回调
dispatch_source_set_cancel_handler(self.timer, ^{
NSLog(@"timer cancelled---%@", [NSThread currentThread]);
});
// 启动定时器
dispatch_resume(self.timer);
}
- (void)dealloc {
NSLog(@"%s", __func__);
// 取消定时器
dispatch_source_cancel(self.timer);
}
@end
// 打印
15:15:24.073246+0800 Demo[17534:9809826] timer running---<NSThread: 0x6000035f2bc0>{number = 8, name = (null)}
15:15:25.073340+0800 Demo[17534:9809827] timer running---<NSThread: 0x6000035c5000>{number = 8, name = (null)}
15:15:26.155698+0800 Demo[17534:9809827] timer running---<NSThread: 0x6000035c5000>{number = 6, name = (null)}
15:15:27.247158+0800 Demo[17534:9809775] -[ViewController dealloc]
15:15:27.247717+0800 Demo[17534:9809827] timer cancelled---<NSThread: 0x6000035c5000>{number = 5, name = (null)}
2,说明
-
定时器在运行或取消状态下,调用
dispatch_resume
函数会crash -
它不受
runloop
的影响,所以比NSTimer
和CADisplayLink
都准时
网友评论