线程中的Timer

突然有个疑问: 在一个子线程中启动一个timer,但是不添加到Runloop中,调用timer.fire(),这时候timer 会运行吗?

实践出真知 😝

   var  times = 1;
        let thread = Thread { 
            let   timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
                print("repeating \(Date.init()) times = \(times)")
                if(times < 20){
                    times += 1
                }else{
                    timer.invalidate()
                }
                
            })
            timer.fire()
            //RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            print(timer.fireDate)
            RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop运行后 在10s 后退出
             //RunLoop.current.run(until: Date.distantFuture)
            print(timer.fireDate)
        }
        
        print("1 \(thread.isExecuting)")
        thread.start()
        print("2 \(thread.isExecuting)")
        let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
        DispatchQueue.global().asyncAfter(deadline:disTime) {
            print("3 \(thread.isExecuting)")
            print(thread)
            print(Thread.current)
        }

输出结果是:


1 false
2 false
repeating 2017-03-26 02:38:35 +0000 times = 1
2017-03-26 02:38:36 +0000
2017-03-26 02:38:36 +0000
3 false
<NSThread: 0x60000026f740>{number = 3, name = (null)}
<NSThread: 0x600000271b00>{number = 4, name = (null)}

在没有将timer add 到Runloop 中&& runloop 停止之前, timer 仅仅触发了一次执行操作。

WHY ?

到底这个timer 在线程中一直执行没有呢?很显然,他就执行一次(这与RunLoop 有何关系?)
那是不是Timer 执行完就被释放了呢,我们再看看3s 后 这个timer 是否还有效,times < 2, 添加3s 后检查timer.isvalide

  var  times = 1;
        let thread = Thread { 
            let   timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
                print("repeating \(Date.init()) times = \(times)")
                if(times < 2){
                    times += 1
                }else{
                    timer.invalidate()
                }
                
            })
            timer.fire()
            //RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            print(timer.fireDate)
            RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop运行后 在10s 后退出
             //RunLoop.current.run(until: Date.distantFuture)
            print(timer.fireDate)
            DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(3), execute: {
                print("after 3s  timer is running \(timer.isValid )")
            })
        }
        
        print("1 \(thread.isExecuting)")
        thread.start()
        print("2 \(thread.isExecuting)")
        let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
        DispatchQueue.global().asyncAfter(deadline:disTime) {
            print("3 \(thread.isExecuting)")
            print(thread)
            print(Thread.current)
            
        }
        
        

在看输出:


1 false
2 true
repeating 2017-03-26 03:01:41 +0000 times = 1
2017-03-26 03:01:42 +0000
2017-03-26 03:01:42 +0000
after 3s  timer is running true
3 false
<NSThread: 0x60000007f100>{number = 3, name = (null)}
<NSThread: 0x600000261900>{number = 4, name = (null)}

我认为 timer 就是一个线程,没有将其加入到Runloop ,该timer执行完他的代码就退出了。

可是线程要Runloop 干嘛呢?不是没有runLoop 线程也可以执行吗?确实是。
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出

CFRunLoopTimerRef 是基于时间的触发器,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调。

根据这个说法那就不难理解,如果不添加到Runloop ,Runloop 没有可接收的消息源,所在线程执行完后就退出。

一般滑动列表的时候我们还有一个timer 在运行,发现Timer 的回调不执行。原因有二

  1. 滑动列表是在TrackingMode,Timer 在defaultMode
  2. 同一时刻Runloop只对应一个Mode

从timer 的mode 切换到 trackingMode,Timer 的回调不执行,但是再次执行的时候会顺延至指定的间隔的整数倍(比如我们4:10 开启,每隔1m 调用一次,在4:12 切换到TrackingMode 4 m 后再切回来,那下次启动大概就是4:17 左右开始回调执行)

参考

Runloop的add 方法

func add(_ timer: Timer, forMode mode: RunLoopMode)
Description
Registers a given timer with a given input mode.
You can add a timer to multiple input modes. While running in the designated mode, the receiver causes the timer to fire on or after its scheduled fire date. Upon firing, the timer invokes its associated handler routine, which is a selector on a designated object.
The receiver retains aTimer. To remove a timer from all run loop modes on which it is installed, send an invalidate() message to the timer.

深入理解RunLoop

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容