NSTimer

一.线程阻塞问题

1.主线程

NSTimer_第1张图片
主界面添加一个 UITabView, 程序启动后拖动 UITabView .

(1) NSRunLoopMode : NSDefaultRunLoopMode

控制台显示,拖动 UI 期间定时器停止打印.


NSTimer_第2张图片
NSRunLoopCommonModes

(2) NSRunLoopMode : NSRunLoopCommonModes 

拖动 UI 期间定时器不停止

总结:主线程的阻塞与 NSRunLoopMode 有关.

2.子线程

NSTimer_第3张图片
子线程运行 timer

此时会阻塞子线程,待 timer 倒计时结束后才会依次执行之后的方法.

(1)拖动 UI 不会阻塞 timer 计时.

(2)与 NSRUNLoopMode 无关.

(3)repeats  如果设置为 yes,将永远不会执行下面这行代码.

 NSLog(@"222当前线程:%@",[NSThread currentThread]);

注意: timer 添加到子线程的Runloop 中时,需要启动 Runloop.

[[NSRunLoop currentRunLoop] run];

二.不能释放当前对象问题

NSTimer_第4张图片
界面布局
NSTimer_第5张图片
控制器代码及 log 信息

实际使用 timer 的过程中,我们经常会有如下场景.

如果我就是想让这个 NSTimer 一直输出,直到 ViewController 销毁了才停止,我该如何让它停止呢?

NSTimer 被 Runloop 强引用了,如果要释放就要调用 invalidate 方法。

但是我想在 ViewController 的 dealloc 里调用 invalidate 方法,但是 self 被 NSTimer 强引用了。

所以我还是要释放 NSTimer 先,然而不调用 invalidate 方法就不能释放它。

然而你不进入到 dealloc 方法里我又不能调用 invalidate 方法。

嗯…

此时 timer 就会一直持有当前对象,当控制器 dismiss 时,并不会执行 dealloc 方法, timer 也不会被销毁.

解决方法:

我们可以造个假的 target 给 NSTimer.这个假的 target 类似于一个中间的代理人,它做的唯一的工作就是挺身而出接下了 NSTimer 的强引用.

参考地址:NSTimer

源码地址:源码地址


NSTimer_第6张图片
亲测有效

iOS10之后系统出了如下方法

+ (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));

+ (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));

看起来跟文章中给出的方法差不多,但是测试并没有解决这个问题.

你可能感兴趣的:(NSTimer)