• 探索 NSRunLoop (一)(NSRunloop 运行机制探索)


      

     说到RunLoop,无论从项目代码或者网上都经常会看到以下这段代码:

        while (!_isFinish)

        {

            NSRunLoop *runloop = [NSRunLoop currentRunLoop];

            [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

        }

    究竟[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]干啥的?

    本文最重要的是要说明白这个事情!准备好开始了.(如果对这部分探索过程看不下去可直接跳到第二部分,第二部分是根据第一部分的结果写出来的demo).

    对于single view application的应用程序,UIApplicationMain()方法在这里不仅完成了初始化我们的程序并设置程序Delegate的任务,而且随之开启了主线程的Run Loop, 开始接受处理事件。

      从简单开始,通过监听runloop状态,查看进入程序什么都不干,runloop会干点啥。

      监听代码如下:

      
      

      

      

    runLoopActivityStringWithActivity函数只是简单的把值转换成对应的文本方便查看。

    打印结果如下:

      

    log出来CFRunLoopActivity对应着以下枚举看。

    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry         = (1UL << 0), // 即将进入Loop
        kCFRunLoopBeforeTimers  = (1UL << 1), // 即将处理 Timer
        kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
        kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
        kCFRunLoopAfterWaiting  = (1UL << 6), // 刚从休眠中唤醒
        kCFRunLoopExit          = (1UL << 7), // 即将退出Loop
    }; 

    可知道:程序在经过了一系列变化后进入了kCFRunLoopBeforeWaiting休眠状态。

     

    然后在viewController里加入个按钮button one,响应代码如下:


      

    点击后打印结果:

     

    这时候可以看one button tap begin 往前三行,输出了kCFRunLoopAfterWaiting

    主线程被换醒,然后处理按钮事件,接着过了一阵子就会从新进入休眠,等待下一事件。

    继续往下,我又加了一个button two。并把代码修改成如下,大家都知道,点击了
    button one 后就进入了死循环,点击button two 是不起作用的。这里就不上Log了。

    但是把button one 代码改成下面这样,就算button one代码没有执行完,同样可以
    在主线程响应button two的事件。究竟

    [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

    做了什么事情呢?

    此时打印出来的log如下:

    从log中看到并没有打印出one button End.说明one button 还没有执行完。

    但是我们可以看到one button before和after RunLoop被打印了好几次,并且CFRunLoopActivity

    打印出来好几次kCFRunLoopEntry和kCFRunLoopExit.说明RunLoop是有退出和重新进入的。不是说主线程的runLoop不会退出的吗?

    难道打出来的不是主线程的runLoop?下面就慢慢说明白这些东西

    为了方便理解,我会把启动时应用给我们创建的RunLoop叫做RunLoop对象,可以这样说RunLoop对象调用runMode创建了一个循环,这个循环可以在有事件发生里处理

    事件,没事发生就会休眠,等待事件发生。那为什么开始没改代码时那种情况为什么响应不了button two的事件呢,那是因为处理button one事件没还返回给系统,系统给我们创建的这个循环并不能往下走了,所以在系统创建的循环处理不了button two。而修改代码后,[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]其实是为RunLoop对象创建了个新的循环。创建一个循环只会有一个kCFRunLoopEntry和kCFRunLoopExit,中间的CFRunLoopActivity状态则要看情况而定,如有哪个输入源等。到达kCFRunLoopExit表明这个循环要退出。由于while中一直为true,由我们代码创循环会不停被启动。[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]创建的循环我叫它子循环,button two 事件其实是在这个子循环里被处理。所以RunLoop对象的循环可以有多个,并且是嵌套的。事件处理会被嵌套最深的那个子循环处理。为了证实这个说法继续加了个button three,并把button two 代码修改,代码如下

    连续点击button one two there.在three中打个断点。调用栈如下:

    很明显看到,button two的事件是在one中创建的子循环执行,而button three的事件是在two中创建的子

    循环执行。

    总结:

    1、[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]其实是为线程创建

    一个循环,如果线程已经有,创建的是一个子循环。

    2、通过[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]创建的循环过一段时间或

    马上返回,这取决于输入源及系统的调度。所以用while进行不断驱动,不停创建循环。

    3、我们看到日志打印出kCFRunLoopExit是子循环的exit.

     

    作者:xianmingchen
    出处:http://www.cnblogs.com/chenxianming/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任权利。
  • 相关阅读:
    CentOS_关机与重启命令详解
    去除ArrayList重复的对象
    单项设计模式
    死循环的应用
    java学习心得-面向对象与面向过程
    计算机使用个人经验及日常维护
    linux操作系统简介
    集合
    项目学习4
    周末总结
  • 原文地址:https://www.cnblogs.com/chenxianming/p/5527498.html
Copyright © 2020-2023  润新知