iOS 中RunLoop 原理與核心機制

來源:互聯網
上載者:User

iOS 中RunLoop 原理與核心機制

目錄[-]

  • RunLoop的定義
  • 目的
  • 理解
  • 特性
  • RunLoop機制
  • RunLoop 運行時調用棧
  • RunLoop支援的訊息事件(Events)
  • Run Loop Modes
  • Run Loop應用實踐RunLoop的定義

    當有持續的非同步任務需求時,我們會建立一個獨立的生命週期可控的線程。RunLoop就是控制線程生命週期並接收事件進行處理的機制。

    RunLoop是iOS事件響應與任務處理最核心的機制,它貫穿iOS整個系統。

    Foundation: NSRunLoopCore Foundation: CFRunLoop 核心部分,代碼開源,C 語言編寫,跨平台

    目的

    通過RunLoop機制實現省電,流暢,響應速度快,使用者體驗好

    理解

    進程是一家工廠,線程是一個流水線,Run Loop就是流水線上的主管;當工廠接到商家的訂單分配給這個流水線時,Run Loop就啟動這個流水線,讓流水線動起來,生產產品;當產品生產完畢時,Run Loop就會暫時停下流水線,節約資源。RunLoop管理流水線,流水線才不會因為無所事事被工廠銷毀;而不需要流水線時,就會辭退RunLoop這個 主管,即退出線程,把所有資源釋放。

    RunLoop並不是iOS平台的專屬概念,在任何平台的多線程編程中,為控制線程的生命週期,接收處理非同步訊息都需要類似RunLoop的迴圈機制實現,Android的Looper就是類似的機制。

    特性
    • 主線程的RunLoop在應用啟動的時候就會自動建立

    • 其他線程則需要在該線程下自己啟動

    • 不能自己建立RunLoop

    • RunLoop並不是安全執行緒的,所以需要避免在其他線程上調用當前線程的RunLoop

    • RunLoop負責管理autorelease pools

    • RunLoop負責處理訊息事件,即輸入源事件和計時器事件

      RunLoop機制

      主線程 (有 RunLoop 的線程) 幾乎所有函數都從以下六個之一的函數調起:

      • CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION

        CFRunloop is calling out to an abserver callback function

        用於向外部報告 RunLoop 目前狀態的更改,架構中很多機制都由 RunLoopObserver 觸發,如 CAAnimation

      • CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK

        CFRunloop is calling out to a block

        訊息通知、非延遲的perform、dispatch調用、block回調、KVO

      • CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUECFRunloop is servicing the main desipatch queue

      • CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION

        CFRunloop is calling out to a timer callback function

        延遲的perform, 延遲dispatch調用

      • CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION

        CFRunloop is calling out to a source 0 perform function

        處理App內部事件、App自己負責管理(觸發),如UIEvent、CFSocket。普通函數調用,系統調用

      • CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION

        CFRunloop is calling out to a source 1 perform function

        由RunLoop和核心管理,Mach port驅動,如CFMachPort、CFMessagePort

      • RunLoop 架構

        ??

        <喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHVsPgo8bGk+CjxwPgpSdW5Mb29wINTL0NDKsTwvcD4KCjxwPgo8YSB0YXJnZXQ9"_blank" href="http://www.bkjia.com/uploads/allimg/160402/041JJ260-1.jpg" target="_blank">

        主要有以下六種狀態:

        • kCFRunLoopEntry -- 進入runloop迴圈

        • kCFRunLoopBeforeTimers -- 處理定時調用前回調

        • kCFRunLoopBeforeSources -- 處理input sources的事件

        • kCFRunLoopBeforeWaiting -- runloop睡眠前調用

        • kCFRunLoopAfterWaiting -- runloop喚醒後調用

        • kCFRunLoopExit -- 退出runloop

          RunLoop 運行時調用棧
          • 主線程App運行時

            • RunLoopObserver與Autorelease Pool的關係

              UIKit 通過 RunLoopObserver 在 RunLoop 兩次 Sleep 間對 Autorelease Pool 進行 Pop 和 Push 將這次 Loop 中產生的 Autorelease 對象釋放。

              • RunLoop的掛起與喚醒

                指定用於喚醒的mach_port連接埠

                調用mach_msg監聽喚醒連接埠,被喚醒前系統核心將這個線程掛起,停留在mach_msg_trap狀態。

                由另一個線程向核心發送這個連接埠的msg後,trap狀態被喚醒,RunLoop繼續工作。

                RunLoop支援的訊息事件(Events)
                • RunLoop

                  • 支援接收處理輸入源(Input Source)事件,包括:

                    系統的Mach Port事件,是一種通訊事件自訂輸入事件

                  • 支援接受處理定時源(Timer)事件

                  • 在啟動RunLoop之前,必須添加監聽的輸入源事件或者定時源事件,否則調用[runloop run]會直接返回,而不會進入迴圈讓線程長駐。

                    如果沒有添加任何輸入源事件或Timer事件,線程會一直在無限迴圈空轉中,會一直佔用CPU時間片,沒有實現資源的合理分配。沒有while迴圈且沒有添加任何輸入源或Timer的線程,線程會直接完成,被系統回收。

                    //錯誤做法NSRunLoop*runLoop=[NSRunLoopcurrentRunLoop];while(!self.isCancelled&&!self.isFinished){[runLooprunUntilDate:[NSDatedateWithTimeIntervalSinceNow:3]];};//正確做法NSRunLoop*runLoop=[NSRunLoopcurrentRunLoop];[runLoopaddPort:[NSMachPortport]forMode:NSDefaultRunLoopMode];while(!self.isCancelled&&!self.isFinished){@autoreleasepool{[runLooprunUntilDate:[NSDatedateWithTimeIntervalSinceNow:3]];}}

                    Run Loop Modes
                    • 理解Run Loop Mode就是流水線上支援生產的產品類型,流水線在一個時刻只能在一種模式下運行,生產某一類型的產品。訊息事件就是訂單。

                    • Cocoa定義了四中Mode

                      Default:NSDefaultRunLoopMode,預設模式,在Run Loop沒有指定Mode的時候,預設就跑在Default Mode下

                      Connection:NSConnectionReplyMode,用來監聽處理網路請求NSConnection的事件

                      Modal:NSModalPanelRunLoopMode,OS X的Modal面板事件

                      Event tracking:UITrackingRunLoopMode,拖動事件

                      Common mode:NSRunLoopCommonModes,是一個模式集合,當綁定一個事件來源到這個模式集合的時候就相當於綁定到了集合內的每一個模式

                    • RunLoop可以通過 [acceptInputForMode:beforeDate:]和[runMode:beforeDate:]來指定在一段時間內的運行模式。如果不 指定的話,RunLoop預設會運行在Default下(不斷重複調用runMode:NSDefaultRunLoopMode beforDate:)

                    • 在主線程啟動一個計時器Timer,然後拖動UITableView或者 UIScrollView,計時器不執行。這是因為,為了更好的使用者體驗,在主線程中Event tracking模式的優先順序最高。在使用者拖動控制項時,主線程的Run Loop是運行在Event tracking Mode下,而建立的Timer是預設關聯為Default Mode,因此系統不會立即執行Default Mode下接收的事件。解決方案:

                      NSTimer*timer=[NSTimerscheduledTimerWithTimeInterval:1.0target:selfselector:@selector(timerFireMethod:)userInfo:nilrepeats:YES];[[NSRunLoopmainRunLoop]addTimer:timerforMode:NSRunLoopCommonModes];//或[[NSRunLoopcurrentRunLoop]addTimer:timerforMode:UITrackingRunLoopMode];[timerfire];

                      Run Loop應用實踐

                      Run Loop主要有以下三個應用情境:

                      • 維護線程的生命週期,讓線程不自動結束,isFinished為Yes時退出。

                        NSRunLoop*runLoop=[NSRunLoopcurrentRunLoop];[runLoopaddPort:[NSMachPortport]forMode:NSDefaultRunLoopMode];while(!self.isCancelled&&!self.isFinished){@autoreleasepool{[runLooprunUntilDate:[NSDatedateWithTimeIntervalSinceNow:3]];}}

                        • 建立常駐線程,執行一些會一直存在的任務。該線程的生命週期跟App相同

                          @autoreleasepool{NSRunLoop*runLoop=[NSRunLoopcurrentRunLoop];[runLoopaddPort:[NSMachPortport]forMode:NSDefaultRunLoopMode];[runLooprun];}

                          • 在一定時間內監聽某種事件,或執行某種任務的線程

                            如下代碼,在30分鐘內,每隔30s執行onTimerFired:。這種情境一般會出現在,如我需要在應用啟動之後,在一定時間內持續更新某項資料。

                            @autoreleasepool{NSRunLoop*runLoop=[NSRunLoopcurrentRunLoop];NSTimer*udpateTimer=[NSTimertimerWithTimeInterval:30target:selfselector:@selector(onTimerFired:)userInfo:nilrepeats:YES];[runLoopaddTimer:udpateTimerforMode:NSRunLoopCommonModes];[runLooprunUntilDate:[NSDatedateWithTimeIntervalSinceNow:60*30]];}

                            • AFNetworking中RunLoop的建立

                              +(void)networkRequestThreadEntryPoint:(id)__unusedobject{@autoreleasepool{[[NSThreadcurrentThread]setName:@"AFNetworking"];NSRunLoop*runLoop=[NSRunLoopcurrentRunLoop];//這裡主要是監聽某個port,目的是讓這個Thread不會回收[runLoopaddPort:[NSMachPortport]forMode:NSDefaultRunLoopMode];[runLooprun];}}+(NSThread*)networkRequestThread{staticNSThread*_networkRequestThread=nil;staticdispatch_once_toncePredicate;dispatch_once(&oncePredicate,^{_networkRequestThread=[[NSThreadalloc]initWithTarget:selfselector:@selector(networkRequestThreadEntryPoint:)object:nil];[_networkRequestThreadstart];});return_networkRequestThread;}

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.