一.线程阻塞问题
1.主线程

(1) NSRunLoopMode : NSDefaultRunLoopMode
控制台显示,拖动 UI 期间定时器停止打印.

(2) NSRunLoopMode : NSRunLoopCommonModes
拖动 UI 期间定时器不停止
总结:主线程的阻塞与 NSRunLoopMode 有关.
2.子线程

此时会阻塞子线程,待 timer 倒计时结束后才会依次执行之后的方法.
(1)拖动 UI 不会阻塞 timer 计时.
(2)与 NSRUNLoopMode 无关.
(3)repeats 如果设置为 yes,将永远不会执行下面这行代码.
NSLog(@"222当前线程:%@",[NSThread currentThread]);
注意: timer 添加到子线程的Runloop 中时,需要启动 Runloop.
[[NSRunLoop currentRunLoop] run];
二.不能释放当前对象问题


实际使用 timer 的过程中,我们经常会有如下场景.
如果我就是想让这个 NSTimer 一直输出,直到 ViewController 销毁了才停止,我该如何让它停止呢?
NSTimer 被 Runloop 强引用了,如果要释放就要调用 invalidate 方法。
但是我想在 ViewController 的 dealloc 里调用 invalidate 方法,但是 self 被 NSTimer 强引用了。
所以我还是要释放 NSTimer 先,然而不调用 invalidate 方法就不能释放它。
然而你不进入到 dealloc 方法里我又不能调用 invalidate 方法。
嗯…
此时 timer 就会一直持有当前对象,当控制器 dismiss 时,并不会执行 dealloc 方法, timer 也不会被销毁.
解决方法:
我们可以造个假的 target 给 NSTimer.这个假的 target 类似于一个中间的代理人,它做的唯一的工作就是挺身而出接下了 NSTimer 的强引用.
参考地址:NSTimer
源码地址:源码地址

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));
看起来跟文章中给出的方法差不多,但是测试并没有解决这个问题.
网友评论