iOS RunLoop 總結以及相關面試題解答

Runloop

Runloop是事件接收和分發機制的一個實現。是線程相關的基礎框架的一部分。一個Runloop就是一個事件處理的循環,用來不停的調度工做及處理輸入事件。使用runloop的目的就是讓你的線程面試

RunLoop的主要目的安全

保證程序執行的線程不會被系統終止,若是沒有RunLoop,UIApplicationMain函數執行完畢以後將直接返回,就是說程序一啓動而後就結束,在有工做的時候忙於工做,而沒有工做的時候處於休眠狀態,bash

何時使用Runloop框架

當須要和該線程進行交互的時候纔會使用Runloop函數

Runloop Mode

一個Runloop可能有幾個modeoop

Runloop Mode 其實是 SourceTimerObserver 的集合,不一樣的 Mode 把不一樣組的 SourceTimerObserver 隔絕開來。Runloop 在某個時刻只能跑在一個 Mode 下,處理這一個 Mode 當中的 Source,Timer 和 Observer。優化

蘋果文檔中提到的 Mode 有五個,分別是:spa

  • NSDefaultRunLoopMode:默認的mode,正常狀況下都是在這個mode線程

  • NSConnectionReplyMode指針

  • NSModalPanelRunLoopMode

  • NSEventTrackingRunLoopMode:使用這個Mode去跟蹤來自用戶交互的事件(好比UITableView上下滑動)

  • NSRunLoopCommonModes

iOS 中公開暴露出來的只有 NSDefaultRunLoopModeNSRunLoopCommonModesNSRunLoopCommonModes 其實是一個 Mode 的集合,默認包括 NSDefaultRunLoopModeNSEventTrackingRunLoopMode

Source

便可以喚醒Runloop的一些事件。好比用戶點擊了屏幕,就會建立一個input source。

  • source0 : 非系統事件

只包含了一個回調(函數指針),它並不能主動觸發事件。使用時,你須要先調用 CFRunLoopSourceSignal(source),將這個 Source 標記爲待處理,而後手動調用 CFRunLoopWakeUp(runloop) 來喚醒 RunLoop,讓其處理這個事件。

  • source1 : 系統事件

包含了一個 mach_port和一個回調(函數指針),被用於經過內核和其餘線程相互發送消息。這種 Source 能主動喚醒 RunLoop 的線程

Timer

咱們常常用的NSTimer就屬於這一類。

Observer

某個observer能夠監聽runloop的狀態變化,並做出必定反應。

RunLoop運行流程

經典大圖

沒有事情的時候,Runloop處於休眠狀態。當外部source將其喚醒後,它會依次處理接收到的timer/source,而後再次進入休眠。

常見的面試題:

Runloop和線程是什麼關係?

每條線程都有惟一的一個與之對應的RunLoop對象,其關係是保存在一個全局的 Dictionary 裏;主線程的RunLoop已經自動建立,子線程的RunLoop須要主動建立;RunLoop在第一次獲取時建立,在線程結束時銷燬

Runloop的mode做用是什麼?

指定事件在運行循環中的優先級的,

線程的運行須要不一樣的模式,去響應各類不一樣的事件,去處理不一樣情境模式。(好比能夠優化tableview的時候能夠設置UITrackingRunLoopMode下不進行一些操做,好比設置圖片等。)

+scheduledTimerWithTimeInterval:的方式觸發的timer,在滑動頁面上的列表時,timer會暫停回調, 爲何?

滑動scrollView時,主線程的RunLoop會切換到UITrackingRunLoopMode這個Mode,執行的也是UITrackingRunLoopMode下的任務(Mode中的item),而timer是添加在NSDefaultRunLoopMode下的,因此timer任務並不會執行,只有當UITrackingRunLoopMode的任務執行完畢,runloop切換到NSDefaultRunLoopMode後,纔會繼續執行timer。

如何解決在滑動頁面上的列表時,timer會暫停回調?

Timer放到NSRunLoopCommonModes中執行便可

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
複製代碼

NSTImer使用時須要注意什麼?

  • 注意timer添加到runloop時應該設置爲何mode
  • 注意timer在不須要時,必定要調用invalidate方法使定時器失效,不然得不到釋放

RunLoop 有哪些應用?

常駐內存、AutoreleasePool 自動釋放池

AutoreleasePoolRunLoop 有什麼聯繫?

iOS應用啓動後會註冊兩個 Observer 管理和維護 AutoreleasePool。應用程序剛剛啓動時默認註冊了不少個Observer,其中有兩個Observer的 callout 都是 _ wrapRunLoopWithAutoreleasePoolHandler,這兩個是和自動釋放池相關的兩個監聽。

  • 第一個 Observer 會監聽 RunLoop 的進入,它會回調objc_autoreleasePoolPush() 向當前的 AutoreleasePoolPage 增長一個哨兵對象標誌建立自動釋放池。這個 Observer 的 order 是 -2147483647 優先級最高,確保發生在全部回調操做以前。

  • 第二個 Observer 會監聽 RunLoop 的進入休眠和即將退出 RunLoop 兩種狀態,在即將進入休眠時會調用 objc_autoreleasePoolPop() 和 objc_autoreleasePoolPush() 根據狀況從最新加入的對象一直往前清理直到遇到哨兵對象。而在即將退出 RunLoop 時會調用objc_autoreleasePoolPop() 釋放自動自動釋放池內對象。這個Observer 的 order 是 2147483647 ,優先級最低,確保發生在全部回調操做以後。

NSRunLoop 和 CFRunLoopRef 區別

CFRunLoopRef 基於C 線程安全,NSRunLoop 基於 CFRunLoopRef 面向對象的API 是不安全的

備註

因爲做者水平有限,不免出現紕漏,若有問題還請不吝賜教。

相關文章
相關標籤/搜索