
目錄
一,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];
// 自動(dòng)添加到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,解決循環(huán)引用
/**
self強(qiáng)引用timer,timer強(qiáng)引用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 { // 消息轉(zhuǎn)發(fā)
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;
}
// 消息轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
@end
- 說明
1>它跟
NSObject是同一級(jí)別的2>它專用于消息轉(zhuǎn)發(fā)
3>用它做代理對(duì)象效率更高,因?yàn)樗侵苯訄?zhí)行消息轉(zhuǎn)發(fā)的,而
NSObject需要先執(zhí)行消息發(fā)送和動(dòng)態(tài)方法解析
二,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)];
// 設(shè)置每秒執(zhí)行1次
self.link.preferredFramesPerSecond = 1;
[self.link addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
}
- (void)linkTask {
NSLog(@"%s", __func__);
// 下一次執(zhí)行的時(shí)間 - 當(dāng)前時(shí)間
NSLog(@"%f", self.link.targetTimestamp - self.link.timestamp);
// 兩幀之間的時(shí)間間隔
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,說明
它是一個(gè)與屏幕刷新相關(guān)的定時(shí)器
屏幕刷新頻率是60
FPS,所以它默認(rèn)每秒執(zhí)行60次duration是按照60FPS來計(jì)算的(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);
// 創(chuàng)建定時(shí)器并設(shè)置執(zhí)行任務(wù)的隊(duì)列
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 每1秒執(zhí)行一次任務(wù)并允許有1秒的誤差
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 1.0 * NSEC_PER_SEC);
// 定時(shí)器任務(wù)
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"timer running---%@", [NSThread currentThread]);
});
// 定時(shí)器被取消的回調(diào)
dispatch_source_set_cancel_handler(self.timer, ^{
NSLog(@"timer cancelled---%@", [NSThread currentThread]);
});
// 啟動(dòng)定時(shí)器
dispatch_resume(self.timer);
}
- (void)dealloc {
NSLog(@"%s", __func__);
// 取消定時(shí)器
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,封裝
// YJTimer.h
@interface YJTimer : NSObject
- (instancetype)initWithInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats
async:(BOOL)async
block:(void(^)(YJTimer *timer))block;
- (void)start;
- (void)cancel;
@end
// YJTimer.m
@interface YJTimer ()
@property (nonatomic, strong) dispatch_source_t timer;
@end
@implementation YJTimer
- (instancetype)initWithInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats
async:(BOOL)async
block:(void(^)(YJTimer *timer))block {
if (self = [super init]) {
dispatch_queue_t queue;
if (async) {
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
} else {
queue = dispatch_get_main_queue();
}
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, interval * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
__weak typeof(self) weakSelf = self;
dispatch_source_set_event_handler(self.timer, ^{
if (block) {
block(weakSelf);
}
if (!repeats) {
[weakSelf cancel];
}
});
}
return self;
}
- (void)start {
dispatch_resume(self.timer);
}
- (void)cancel {
dispatch_source_cancel(self.timer);
}
@end
// ViewController
@interface ViewController ()
@property (nonatomic, strong) YJTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [[YJTimer alloc] initWithInterval:1.0
repeats:YES
async:YES
block:^(YJTimer * _Nonnull timer) {
NSLog(@"timer running---%@", [NSThread currentThread]);
}];
[self.timer start];
}
- (void)dealloc {
[self.timer cancel];
}
@end
// 打印
09:50:01.948312+0800 Demo[24436:9961956] timer running---<NSThread: 0x6000026a8140>{number = 8, name = (null)}
09:50:02.949507+0800 Demo[24436:9961960] timer running---<NSThread: 0x6000026aed40>{number = 9, name = (null)}
09:50:03.949519+0800 Demo[24436:9961960] timer running---<NSThread: 0x6000026aed40>{number = 9, name = (null)}
3,說明
定時(shí)器在運(yùn)行或取消狀態(tài)下,調(diào)用
dispatch_resume函數(shù)會(huì)crash它不受
runloop的影響,所以比NSTimer和CADisplayLink都準(zhǔn)時(shí)