1、NSTimer方法解析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//需要加入runloop 需要调用fire启动
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
//需要加入runloop
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;
//会默认加入mainRunLoop中 直接启动
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
通过试验发现:通过-(id)init 和 +(id)timer 方法创建的timer都需要手动加到runloop中才可以执行;通过+(id)scheduledTimer方法创建的timer会自动加入mainRunloop中,并且可以直接执行。
2、关于强引用问题。
通常我们在某个类中使用taget-selector或block去执行的时候,timer会对其强引用。比如在一个视图控制器,当我们使用target-selector时,通常需要在dealloc时调用下面这个方法。当使用block时,还要在代码块中应使用weakSelf。以防止试图控制器和timer相互引用而无法释放。
1
2
3
//在应该销毁Timer的地方调用
- (void)invalidate;
3、定时器不准的问题
首先,NSDefaultRunLoopMode 模式中,程序会优先处理输入源事件,处理输入源事件时,不能处理定时源事件
还有,通常我们都会在主线程创建定时器,但是当主线程阻塞时,定时器也会被阻塞,这样就会造成定时器掉帧、不准。
解决方法:在子线程中创建定时器,如下所示:
1
2
3
4
5
6
7
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timer1Action) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
[timer fire];
[[NSRunLoop currentRunLoop]run];
});