iOS 开发之 RunLoop 详解

        1)什么是 Runloop ?

            1、字面上是运行循环,内部就是 do-while 循环,在这个循环内不断地处理各种任务。

            2、一个线程对应一个 Runloop ,主线程的 RunLoop 默认是开启的。子线程的 RunLoop 需手动开启。

            3、RunLoop 只能对应选择一个 Model 启动,如果当期的 Model 中没有任何 Source(Sources0,Sources1)、Timmer,那么就直接退出 RunLoop。

            4、基本作用就是保持程序的持续运行,处理 APP 中的各种事件、通过 RunLoop ,有事执行,没事休眠,可以节省 CPU 资源,提高程序性能。

 

        2)iOS 中有2套 API 访问和使用 RunLoop

            在 Fundation 框架下:NSRunLoop

            在Core Fundation 下:CFRunLoopRef

        比较:

            1、NSRunLoop 和 CFRunLoopRef 都代表 RunLoop 对象

            2、NSRunLoop 是基于 CFRunLoopRef 的一层 OC 封装。

 

        3)RunLoop 与 线程:

            1、每条线程都有唯一对应的 RunLoop 对象;

            2、主线程的 RunLoop 已经自动创建好了,子线程的 RunLoop 需要主动创建

            3、RunLoop 在第一次获取时创建,在线程结束时销毁。

 

        4)获取 RunLoop 对象:

            Fundation 框架:

                [NSRunLoop currentRunLoop];//获取当前线程的 RunLoop 对象

                [NSRunLoop mainRunLoop];//获取主线程的 RunLoop 对象

            Core Fundation 框架:

                CFRunLoopGetCurrent();  // 获取当前线程的 RunLoop 对象

                CFRunLoopGetMain(); //获取主线程的 RunLoop 对象

 

        5)RunLoop 处理逻辑:

            1、通知 Observer:即将进入 Loop

            2、通知 Observer:即将处理 Timer

            3、通知 Observer:将要处理 Source0

            4、处理 Source0

            5、如果有 Source0,跳到步骤 9

            6、通知 Observer:线程即将休眠

            7、休眠,等待唤醒:

                    1> Source0(port)

                    2> timer 启动

                    3> RunLoop 设置的 timer 已经超时

                    4> RunLoop 被外部手动唤醒

            8、通知 Observer:线程将被唤醒

            9、处理未处理的时间:

                    1> 如果用户定义的定时器启动,处理定时器事件并重启 RunLoop。进入步骤 2

                    2> 如果输入源启动,传递相应的消息

                    3> 如果 RunLoop 被显式唤醒而且时间还没超时,重启 RunLoop,进入步骤 2

            10、通知 Observer:即将推出 Loop

 

        6)RunLoop 应用场景:

            NSTimer

            ImageView 显示

            PerformSelector

            常驻线程

            自动释放池

 

                应用场景:

                    1> 开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件)

                    2> 在子线程中开启一个定时器

                    3> 在子线程中进行一些长期监控

                    4> 可以控制定时器在特定模式下执行

                    5> 可以让某些事件(行为、任务)在特定模式下执行

                    6> 可以添加 Observer 监听 RunLoop 的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)

 

        7)NSRunLoop 的实现机制,及在多线程中如何使用

            程序创建子线程的时候,才需要手动启动 RunLoop,主线程的 RunLoop 默认开启

            在多线程中,你需要判断是否需要 RunLoop,如果需要,那么你负责配置 RunLoop 并启动,你不需要在任何时候都去启动 RunLoop。例如:使用线程去处理一个预定好的耗时极长的任务时,你就可以无需启动 RunLoop。RunLoop 只有在和线程交互时才需要。

 

        8)RunLoop 的 Model 的作用:

            mode 主要用来指定事件在运行循环中的优先级的。

            • NSDefaultRunLoopMode (kCFRunLoopDefaultMode):默认,空闲状态

            • UITrackingRunLoopMode ScrollView:         ScrollView 滑动时会切换到该Mode

            • UIInitializationRunLoopMode run loop:       RunLoop 启动时,会切换到该 mode

 

            如果我们把一个 NSTimer 对象以 NSDefaultRunLoopMode(KCFRunLoopDefaultMOde) 添加到主运行循环中的时候,ScrollView滚动过程中会因为 Mode 的切换,而导致 NSTimer 不在被调度。当我们滚动的时候,也不希望调度,那么就应该使用默认模式。但是,虚妄在滚动时,定时器也要回调,那就应该使用 commonMode。

 

            如果想要销毁 Timer ,则必须先将 Timer 置为失效,否则 Timer 就一直占用内存而不会释放。造成逻辑上的内存泄露。该泄露不会使用 Xcode 工具 Instrument 检测出来、另外对于要求必须销毁的 Timer 的逻辑处理,未将 Timer 置为失效,若每次都创建一次,则之前的不能得到释放,则会同时存在多个 Timer 的实例在内存中。

 

            在 Timer 不需要时,一定要调用 invalidate 方法使定时器失效,否则得不到释放。

 

            如果要 Cell 滚动过程中定时器正常回调,UI 正常刷新,那么要将 Timer 放入 CommonMode 下,因为 NSDefaultRunLoopMode 只有在空闲状态下才会回调。

 

            UIScrollView 的滚动导致 NSTimer 失效:

                1、更改 mode 为 NSRunLoopCommonModes(无论 RunLoop 运行在哪个 Mode都能运行)

                2、切换到主线程来更新 UI 界面刷新

                    // 将timer添加到 NSDefaultRunLoopMode 中

                    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];

                    //  然后再添加到 NSRunLoopCommonModes里

                    NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];

                    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

 

 

 

 

 

 

 

posted @ 2017-08-31 16:03  ZachRobin  阅读(478)  评论(0)    收藏  举报