使用方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
scheduledTimerWith和timerWith和区别
NSTimer是加到runloop中执行的。
- scheduledTimerWith
函数说明,创建并安排到runloop的default mode中
Creates a timer and schedules it on the current run loop in the default mode
- timerWithTimeInterval
如果我们调用的是timerWith接口,就需要自己加入runloop
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(Timered) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
GCD定时器
GCD中的Dispatch Source其中的一种类型是DISPATCH_SOURCE_TYPE_TIMER,可以实现定时器的功能。注意的是需要把timer声明为属性,否则,由于这种timer并不是添加到runloop中的,直接就被释放了。
GCD定时器的好处是,他并不是加入runloop执行的,因此子线程也可以使用。也不会引起循环引用的问题。
WS(weakSelf);
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
[weakSelf commentAnimation];
});
dispatch_resume(timer);
注意事项
子线程启动NSTimer
主线程默认启动了runloop,子线程没有默认的runloop,因此,在子线程启动定时器是不生效的
解决方案
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSTimer* timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(Timered:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
});
循环引用
NSTimer的target被强引用了,而通常target就是所在的控制器,他又强引用了timer,造成了循环引用
不是所有的NSTimer都会造成循环引用。就像不是所有的block都会造成循环引用一样
以下两种timer不会有循环引用:
- 非repeat类型的。非repeat类型的timer不会强引用target,因此不会出现循环引用。
- block类型的,新api。iOS 10之后才支持,因此对于还要支持老版本的app来说,这个API暂时无法使用。当然,block内部的循环引用也要避免
不是解决了循环引用,target就可以释放了,别忘了在持有timer的类dealloc的时候执行invalidate。
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(Timered:) userInfo:nil repeats:YES];
如上面代码,这个timer并没有被self引用,那么为什么self不会被释放呢?因为timer被加到了runloop中,timer又强引用了self,所以timer一直存在的话,self也不会释放。
网友评论