网站/小程序/APP个性化定制开发,二开,改版等服务,加扣:8582-36016

    RunLoop是与线程相关的基础架构中的一部分,它是一个处理事件的循环(线程进入这个循环,运行事件处理程序来响应传入的事件),RunLoop的目的是当有事件需要处理时,线程是活跃的、忙碌的,当没有事件后,线程进入休眠。

    在RunLoop启动之后会发送一个通知,来告知观察者

    将要处理Timer/Source0事件这样一个通知的发送

    处理Source0事件

    如果有Source1要处理,这时会通过一个go to语句的实现来进行代码逻辑的跳转,处理唤醒是收到的消息

    如果没有Source1要处理,线程就将要休眠,同时发送一个通知,告诉观察者

    然后线程进入一个用户态到内核态的切换,休眠,然后等待唤醒,唤醒的条件大约包括三种:

    1、Source1

    2、Timer事件

    3、外部手动唤醒

    线程刚被唤醒之后也要发送一个通知告诉观察者,然后处理唤醒时收到的消息

    回到将要处理Timer/Source0事件这样一个通知的发送

    然后再次进行上面步骤,这就是一个RunLoop的事件循环机制

    内部代码逻辑整理如下:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    95

    96

    97

    98

    99

    100

    101

    102

    103

    104

    105

    106

    107

    108

    109

    110

    /// 用DefaultMode启动

    void CFRunLoopRun(void) {

        CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);

    }

      

    /// 用指定的Mode启动,允许设置RunLoop超时时间

    int CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean stopAfterHandle) {

        return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);

    }

      

    /// RunLoop的实现

    int CFRunLoopRunSpecific(runloop, modeName, seconds, stopAfterHandle) {

         

        /// 首先根据modeName找到对应mode

        CFRunLoopModeRef currentMode = __CFRunLoopFindMode(runloop, modeName, false);

        /// 如果mode里没有source/timer/observer, 直接返回。

        if (__CFRunLoopModeIsEmpty(currentMode)) return;<360>

         

        /// 1. 通知 Observers: RunLoop 即将进入 loop。

        __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopEntry);

         

        /// 内部函数,进入loop

        __CFRunLoopRun(runloop, currentMode, seconds, returnAfterSourceHandled) {

             

            Boolean sourceHandledThisLoop = NO;

            int retVal = 0;

            do {

      

                /// 2. 通知 Observers: RunLoop 即将触发 Timer 回调。

                __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeTimers);

                /// 3. 通知 Observers: RunLoop 即将触发 Source0 (非port) 回调。

                __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeSources);

                /// 执行被加入的block

                __CFRunLoopDoBlocks(runloop, currentMode);

                 

                /// 4. RunLoop 触发 Source0 (非port) 回调。

                sourceHandledThisLoop = __CFRunLoopDoSources0(runloop, currentMode, stopAfterHandle);

                /// 执行被加入的block

                __CFRunLoopDoBlocks(runloop, currentMode);

      

                /// 5. 如果有 Source1 (基于port) 处于 ready 状态,直接处理这个 Source1 然后跳转去处理消息。

                if (__Source0DidDispatchPortLastTime) {

                    Boolean hasMsg = __CFRunLoopServiceMachPort(dispatchPort, &msg)

                    if (hasMsg) goto handle_msg;

                }

                 

                /// 通知 Observers: RunLoop 的线程即将进入休眠(sleep)。

                if (!sourceHandledThisLoop) {

                    __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeWaiting);

                }

                 

                /// 7. 调用 mach_msg 等待接受 mach_port 的消息。线程将进入休眠, 直到被下面某一个事件唤醒。

                /// • 一个基于 port 的Source 的事件。

                /// • 一个 Timer 到时间了

                /// • RunLoop 自身的超时时间到了

                /// • 被其他什么调用者手动唤醒

                __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort) {

                    mach_msg(msg, MACH_RCV_MSG, port); // thread wait for receive msg

                }

      

                /// 8. 通知 Observers: RunLoop 的线程刚刚被唤醒了。

                __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopAfterWaiting);

                 

                /// 收到消息,处理消息。

                handle_msg:

      

                /// 9.1 如果一个 Timer 到时间了,触发这个Timer的回调。

                if (msg_is_timer) {

                    __CFRunLoopDoTimers(runloop, currentMode, mach_absolute_time())

                }

      

                /// 9.2 如果有dispatch到main_queue的block,执行block。

                else if (msg_is_dispatch) {

                    __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);

                }

      

                /// 9.3 如果一个 Source1 (基于port) 发出事件了,处理这个事件

                else {

                    CFRunLoopSourceRef source1 = __CFRunLoopModeFindSourceForMachPort(runloop, currentMode, livePort);

                    sourceHandledThisLoop = __CFRunLoopDoSource1(runloop, currentMode, source1, msg);

                    if (sourceHandledThisLoop) {

                        mach_msg(reply, MACH_SEND_MSG, reply);

                    }

                }

                 

                /// 执行加入到Loop的block

                __CFRunLoopDoBlocks(runloop, currentMode);

                 

      

                if (sourceHandledThisLoop && stopAfterHandle) {

                    /// 进入loop时参数说处理完事件就返回。

                    retVal = kCFRunLoopRunHandledSource;

                } else if (timeout) {

                    /// 超出传入参数标记的超时时间了

                    retVal = kCFRunLoopRunTimedOut;

                } else if (__CFRunLoopIsStopped(runloop)) {

                    /// 被外部调用者强制停止了

                    retVal = kCFRunLoopRunStopped;

                } else if (__CFRunLoopModeIsEmpty(runloop, currentMode)) {

                    /// source/timer/observer一个都没有了

                    retVal = kCFRunLoopRunFinished;

                }

                 

                /// 如果没超时,mode里没空,loop也没被停止,那继续loop。

            } while (retVal == 0);

        }

         

        /// 10. 通知 Observers: RunLoop 即将退出。

        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

    }

    可以看到,实际上 RunLoop 就是这样一个函数,其内部是一个do-while循环。当你调用CFRunLoopRun()时,线程就会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回

    有一个这样的问题:当我们点击一个app,从我们点击到程序启动、程序运行再到程序杀死这个过程,系统都发生了什么呢?

    实际上当我们调用了main函数之后,会调用UIApplicationMain函数,在这个函数内部会启动主线程的RunLoop,然后经过一系列的处理,最终主线程的RunLoop会处于一个休眠状态,然后我们此时如果点击一下屏幕,会转化成一个Source1来让我们的主线程唤醒,然后当我们杀死程序时,会调用RunLoop的退出,同时发送通知告诉观察者

    找到一张总结图帮助记忆:


    评论 0

    暂无评论
    0
    0
    0
    立即
    投稿
    发表
    评论
    返回
    顶部