欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

分析IOS RunLoop的事件循環(huán)機制

 更新時間:2021年06月07日 14:16:47   作者:為童沉淪  
RunLoop是與線程相關的基礎架構中的一部分,它是一個處理事件的循環(huán)(線程進入這個循環(huán),運行事件處理程序來響應傳入的事件),RunLoop的目的是當有事件需要處理時,線程是活躍的、忙碌的,當沒有事件后,線程進入休眠。

在RunLoop啟動之后會發(fā)送一個通知,來告知觀察者

將要處理Timer/Source0事件這樣一個通知的發(fā)送

處理Source0事件

如果有Source1要處理,這時會通過一個go to語句的實現(xiàn)來進行代碼邏輯的跳轉,處理喚醒是收到的消息

如果沒有Source1要處理,線程就將要休眠,同時發(fā)送一個通知,告訴觀察者

然后線程進入一個用戶態(tài)到內核態(tài)的切換,休眠,然后等待喚醒,喚醒的條件大約包括三種:

1、Source1

2、Timer事件

3、外部手動喚醒

線程剛被喚醒之后也要發(fā)送一個通知告訴觀察者,然后處理喚醒時收到的消息

回到將要處理Timer/Source0事件這樣一個通知的發(fā)送

然后再次進行上面步驟,這就是一個RunLoop的事件循環(huán)機制

內部代碼邏輯整理如下:

/// 用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的實現(xiàn)
int CFRunLoopRunSpecific(runloop, modeName, seconds, stopAfterHandle) {
    
    /// 首先根據modeName找到對應mode
    CFRunLoopModeRef currentMode = __CFRunLoopFindMode(runloop, modeName, false);
    /// 如果mode里沒有source/timer/observer, 直接返回。
    if (__CFRunLoopModeIsEmpty(currentMode)) return;
    
    /// 1. 通知 Observers: RunLoop 即將進入 loop。
    __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopEntry);
    
    /// 內部函數(shù),進入loop
    __CFRunLoopRun(runloop, currentMode, seconds, returnAfterSourceHandled) {
        
        Boolean sourceHandledThisLoop = NO;
        int retVal = 0;
        do {
 
            /// 2. 通知 Observers: RunLoop 即將觸發(fā) Timer 回調。
            __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeTimers);
            /// 3. 通知 Observers: RunLoop 即將觸發(fā) Source0 (非port) 回調。
            __CFRunLoopDoObservers(runloop, currentMode, kCFRunLoopBeforeSources);
            /// 執(zhí)行被加入的block
            __CFRunLoopDoBlocks(runloop, currentMode);
            
            /// 4. RunLoop 觸發(fā) Source0 (非port) 回調。
            sourceHandledThisLoop = __CFRunLoopDoSources0(runloop, currentMode, stopAfterHandle);
            /// 執(zhí)行被加入的block
            __CFRunLoopDoBlocks(runloop, currentMode);
 
            /// 5. 如果有 Source1 (基于port) 處于 ready 狀態(tài),直接處理這個 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 到時間了,觸發(fā)這個Timer的回調。
            if (msg_is_timer) {
                __CFRunLoopDoTimers(runloop, currentMode, mach_absolute_time())
            } 
 
            /// 9.2 如果有dispatch到main_queue的block,執(zhí)行block。
            else if (msg_is_dispatch) {
                __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
            } 
 
            /// 9.3 如果一個 Source1 (基于port) 發(fā)出事件了,處理這個事件
            else {
                CFRunLoopSourceRef source1 = __CFRunLoopModeFindSourceForMachPort(runloop, currentMode, livePort);
                sourceHandledThisLoop = __CFRunLoopDoSource1(runloop, currentMode, source1, msg);
                if (sourceHandledThisLoop) {
                    mach_msg(reply, MACH_SEND_MSG, reply);
                }
            }
            
            /// 執(zhí)行加入到Loop的block
            __CFRunLoopDoBlocks(runloop, currentMode);
            
 
            if (sourceHandledThisLoop && stopAfterHandle) {
                /// 進入loop時參數(shù)說處理完事件就返回。
                retVal = kCFRunLoopRunHandledSource;
            } else if (timeout) {
                /// 超出傳入參數(shù)標記的超時時間了
                retVal = kCFRunLoopRunTimedOut;
            } else if (__CFRunLoopIsStopped(runloop)) {
                /// 被外部調用者強制停止了
                retVal = kCFRunLoopRunStopped;
            } else if (__CFRunLoopModeIsEmpty(runloop, currentMode)) {
                /// source/timer/observer一個都沒有了
                retVal = kCFRunLoopRunFinished;
            }
            
            /// 如果沒超時,mode里沒空,loop也沒被停止,那繼續(xù)loop。
        } while (retVal == 0);
    }
    
    /// 10. 通知 Observers: RunLoop 即將退出。
    __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
}

可以看到,實際上 RunLoop 就是這樣一個函數(shù),其內部是一個do-while循環(huán)。當你調用CFRunLoopRun()時,線程就會一直停留在這個循環(huán)里;直到超時或被手動停止,該函數(shù)才會返回

有一個這樣的問題:當我們點擊一個app,從我們點擊到程序啟動、程序運行再到程序殺死這個過程,系統(tǒng)都發(fā)生了什么呢?

實際上當我們調用了main函數(shù)之后,會調用UIApplicationMain函數(shù),在這個函數(shù)內部會啟動主線程的RunLoop,然后經過一系列的處理,最終主線程的RunLoop會處于一個休眠狀態(tài),然后我們此時如果點擊一下屏幕,會轉化成一個Source1來讓我們的主線程喚醒,然后當我們殺死程序時,會調用RunLoop的退出,同時發(fā)送通知告訴觀察者

找到一張總結圖幫助記憶:

以上就是分析IOS RunLoop的事件循環(huán)機制的詳細內容,更多關于IOS RunLoop的事件循環(huán)機制的資料請關注腳本之家其它相關文章!

相關文章

  • Observing?KVO?Key-Value基本使用原理示例詳解

    Observing?KVO?Key-Value基本使用原理示例詳解

    這篇文章主要為大家介紹了Observing?KVO?Key-Value基本使用原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • iOS如何利用一句話完成轉場動畫

    iOS如何利用一句話完成轉場動畫

    這篇文章主要給大家介紹了關于iOS如何利用一句話完成轉場動畫的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-08-08
  • iOS中UIView實現(xiàn)不同方向的導角

    iOS中UIView實現(xiàn)不同方向的導角

    這篇文章主要給大家介紹了關于iOS中UIView實現(xiàn)不同方向的導角的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或使用iOS具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-05-05
  • 剖析iOS開發(fā)中Cocos2d-x的內存管理相關操作

    剖析iOS開發(fā)中Cocos2d-x的內存管理相關操作

    這篇文章主要介紹了剖析iOS開發(fā)中Cocos2d-x的內存管理相關操作,Cocos2d-x是開發(fā)游戲的利器,需要的朋友可以參考下
    2015-10-10
  • IOS 圖文混排(CoreText.framework)詳解及實例

    IOS 圖文混排(CoreText.framework)詳解及實例

    這篇文章主要介紹了IOS 圖文混排(CoreText.framework)詳解及實例的相關資料,這里對IOS 的圖文混排進行了詳細介紹,并附代碼實例,和實現(xiàn)效果圖,需要的朋友可以參考下
    2016-11-11
  • iOS中Xcode 8 日志輸出亂碼問題的解決方法

    iOS中Xcode 8 日志輸出亂碼問題的解決方法

    這篇文章主要介紹了iOS中Xcode 8日志輸出亂碼問題及解決方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • iOS App開發(fā)中Core Data框架基本的數(shù)據管理功能小結

    iOS App開發(fā)中Core Data框架基本的數(shù)據管理功能小結

    除了使用SQL關系型數(shù)據庫,我們還可以使用Xcode中提供的Core Data來進行表結構數(shù)據處理,這里我們就來初步整理iOS App開發(fā)中Core Data框架基本的數(shù)據管理功能小結:
    2016-06-06
  • Swift中的HTTP請求體Request Bodies使用示例詳解

    Swift中的HTTP請求體Request Bodies使用示例詳解

    這篇文章主要為大家介紹了Swift中的HTTP請求體Request Bodies使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • 分析IOS RunLoop的事件循環(huán)機制

    分析IOS RunLoop的事件循環(huán)機制

    RunLoop是與線程相關的基礎架構中的一部分,它是一個處理事件的循環(huán)(線程進入這個循環(huán),運行事件處理程序來響應傳入的事件),RunLoop的目的是當有事件需要處理時,線程是活躍的、忙碌的,當沒有事件后,線程進入休眠。
    2021-06-06
  • iOS去除Webview鍵盤頂部工具欄的方法

    iOS去除Webview鍵盤頂部工具欄的方法

    這篇文章主要給大家介紹了關于iOS去除Webview鍵盤頂部工具欄的相關資料,文中通過示例代碼介紹的非常詳細,對各位iOS開發(fā)者們具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06

最新評論