前言:
這篇文章主要內容是介紹RunLoop的一些概念以及用法:使用RunLoop建立常駐線程、自定義輸入源進行線程通訊等。同時藉此機會但願可以和你們一塊兒討論RunLoop相關的知識,加深對RunLoop的理解。git
RunLoop
是與線程相關的基礎架構中的一部分,它是一個處理事件的循環(線程進入這個循環,運行事件處理程序來響應傳入的事件),RunLoop
的目的是當有事件須要處理時,線程是活躍的、忙碌的,當沒有事件後,線程進入休眠。github
RunLoop結構以及事件來源:微信
一個RunLoop
包含若干個Mode
,每一個Mode
包含若干個Source
/Timer
/Observer
/Port
。當啓動一個RunLoop
時會先指定一個Mode
,檢查指定Mode
是否存在以及Mode
中是否含有Source
和Timer
,若是Mode
不存在或者Mode
中無Source
和Timer
,認爲該Mode
是一個空的Mode
,RunLoop
就直接退出。架構
Port-Based Sources:監聽App
的Mach Port
,由內核發出信號,輸入源收到信號後,執行相關的例程。oop
Custom Input Sources:監聽自定義的輸入源,須要在其它線程手動發送信號,輸入源收到信號後,執行相關的例程。學習
Cocoa Perform Selector Sources:Cocoa
中自定義的輸入源,目的是在不一樣線程中執行任務,同一線程中的任務是順序執行的,當任務執行完成後系統會自動移除這個源。(注意:在目標線程中執行任務時,這個目標線程必須有活躍的RunLoop)線程
時間源會在預設的時間同步傳遞事件給對應的線程,計時器是線程通知本身作某事的一種方式。翻譯
計時器並非真正的實時的,當計時器未處於RunLoop
當前監聽的Mode
,那麼計時器是不會計時調度任務的,只有RunLoop
當前監聽的Mode
是計時器關聯的Mode
時,計時器纔會開始執行任務,例如:NSTimer
添加至主線程RunLoop
的DefaultMode
中,此時滑動TableView
/ScrollView
時,RunLoop
會切換至TrackMode
,計時器是不會調度任務的。3d
若是RunLoop
在執行一個例程時,計時器觸發了,那麼計時器會等待RunLoop
將該例程執行完成,在下一次的循環中處理。在RunLoop
未運行狀況下,計時器永遠不會觸發任務。
應用啓動時,會自動在主線程上設置運行RunLoop
,因此不須要在主線程上顯示的啓動RunLoop
,無需調用[[NSRunLoop currentRunLoop] runUntilDate:]
這些方法。那麼若是咱們顯示的在主線程中調用RunLoop
的run
方法會出現什麼結果呢?經過Demo
中顯示,主線程中顯示啓動RunLoop
會影響當前事件處理,可是因爲RunLoop
並無中止,因此其餘事件可以正常接收和處理。
而子線程也不併是必需要設置運行RunLoop
才能執行任務,好比說只是簡單在子線程中處理個耗時任務等,以下場景是須要啓動RunLoop
的:
NSPort
或者自定義輸入源與其它線程通訊。Cocoa
應用中使用performSelector
相關方法。正如前言中所說,本文主要說明線程常駐和自定義輸入源線程通訊。
方式一:無條件的啓動RunLoop
是最簡單的選擇,但它也是最不可取的選擇,它會將線程置於永久循環中,這樣幾乎沒法控制RunLoop
自己,雖然能夠添加和刪除輸入源和計時器,但中止RunLoop
的惟一方法是殺死RunLoop
。(以上內容是經過Google翻譯的官網內容可能理解有些誤差屆時還望指正,事實上我在作實驗的過程當中,發現使用NSThread
的cancel
方法是沒法中止RunLoop
的,cancel
方法是更改線程的取消狀態,指示它應該退出。在當前線程下執行[NSThread exit]
方法,退出了該線程,但demo
中的LongLifeThreadViewController
仍然未被釋放)
方式二:啓動RunLoop
時設定時限,RunLoop
將一直運行直到事件到達或分配的時間到期。若是事件到達,則將該事件分派給處理程序進行處理,而後退出這次RunLoop
。能夠經過從新啓動RunLoop
處理下一個事件。一樣若是分配的時間到期,也能夠從新啓動RunLoop
來處理。這種方式能夠指定RunLoopMode
,官網力薦。
定義輸入源:
RunLoop
時的執行例程。我的感受能夠根據我的需求決定是否實現第三、4兩條內容。(注意定義輸入源只能經過CoreFoundation提供的對應API實現,其中的回調例程由C語言實現)
在RunLoop
上安裝輸入源:若是實現了上述的第3條內容時,將自定義的輸入源添加到RunLoop
時,就會回調輸入源對應的schedule
實現例程。
向輸入源發送信號:輸入源在接收到信號後,會執行對應的perform
例程,perform
例程就是對應事件處理程序。(注意若是線程處於休眠狀態,要喚醒線程,不然該事件沒法被處理。
結語:
關於RunLoop
的內容還有不少,好比:RunLoopModes
、RunLoopObserver
、NSPort
、NSTimer
等等,固然還有RunLoop
的源碼,這些內容在此並未列出,若有感興趣的小夥伴能夠先行花時間去探索、學習,到時能夠一塊兒交流、討論。
源碼地址:QiRunLoopDemo1
小編微信:可加並拉入《QiShare技術交流羣》。
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)
推薦文章:
iOS 經常使用調試方法:LLDB命令
iOS 經常使用調試方法:斷點
iOS 經常使用調試方法:靜態分析
iOS消息轉發
iOS 自定義拖拽式控件:QiDragView
iOS 自定義卡片式控件:QiCardView
iOS Wireshark抓包
iOS Charles抓包
奇舞週刊