NSTimer
- NSTimer计时器,会被UIScrollView 打断,解决办法
1
2
3self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
self.timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; __weak和block能解除循环引用1
2
3
4__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf test];
}];NSProxy解决循环引用,效率很高,因为不经过Runtime的,消息发送,消息动态解析,去缓存中查找等流程,直接通过消息转发。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@interface YZProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
@implementation YZProxy
+ (instancetype)proxyWithTarget:(id)target {
// NSProxy对象不需要调用init,因为它本来就没有init方法
YZProxy *proxy = [YZProxy alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
@end
// 使用的时候,如下就可以了。
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[YZProxy proxyWithTarget:self] selector:@selector(test) userInfo:nil repeats:YES];
}
- (void)dealloc{
[self.timer invalidate];
}
CADisplayLink
- CADisplayLink是用于同步屏幕刷新频率的计时器,CADisplayLink和NSTimer一样也会导致循环引用,解决办法和前面的NSTimer一样。
dispatch_source_t
NSTimer依赖于RunLoop,如果RunLoop的任务过于繁重,可能会导致NSTimer不准时,这时可以用GCD的定时器。因为是直接跟内核挂钩的,跟RunLoop没有关系,所以也不会有常见的RunLoop模式的改变而导致定时器的暂停等问题1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 主队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 创建定时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 设置时间
uint64_t start = 2.0; // 2秒后开始执行
uint64_t interval = 1.0; // 每隔1秒执行
dispatch_source_set_timer(timer,dispatch_time(DISPATCH_TIME_NOW, start * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0);
// 设置回调
dispatch_source_set_event_handler(timer, ^{
NSLog(@"1111");
});
// 启动定时器
dispatch_resume(timer);
self.GCDtimer = timer;