-
什麼是RunLoop?
-
從字面上來看是運行循環的意思.
-
內部就是一個do{}while循環,在這個循環裏內部不斷的處理各類任務(好比:source/timer/Observer)
-
RunLoop的存在其實就是爲線程而存在的.線程的做用就是執行一個特定的任務,可是默認狀況下線程執行完任務後就不能再次執行任務,這是由於默認狀況下線程是沒有開啓RunLoop的.若是開啓RunLoop以後,線程執行完任務以後,會一直等待,直到再次接受到任務,接續執行任務.線程銷燬前,會先釋放這個線程所對應的RunLoop.
-
RunLoop基本做用
-
保持程序的持續運行,保持線程的持續運行.
-
處理App中的各類事件(好比觸摸事件,定時器事件,Selector事件)
-
節省CPU資源,提升程序性能:該作事時作事,該休息時休息
-
RunLoop對象
-
ios中有2套API來訪問和使用RunLoop
-
一套是Fundation(純OC的)框架中的
-
一套是Core Fundation(純C語言的)框架中的
-
NSRunLoo和CFRunLoopRef都表明着RunLoop對象.NSRunLoop是基於CFRunLoopRef的一層OC包裝
-
RunLoop與線程
-
每條線程都有惟一的一個與之對應的RunLoop對象
-
主線程的Runloop系統已經自動建立好了,子線程的RunLoop須要手動建立
-
RunLoop在第一次獲取時由系統自動建立,在線程結束時銷燬
-
若是想給子線程建立RunLoop,不能直接alloc&init,只要調用獲取當前線程RunLoop方法便可,系統會自動放回當前線程的RunLoop,若是當前線程沒有RunLoop,系統會自動建立.
-
RunLoop相關類
-
Core Fundation中關於RunLoop的5個類
-
CFRunLoopRef: RunLoop對象
-
CFRunLoopModeRef: RunLoop運行模式.
-
CFRunLoopSoruceRef: 事件源(輸入源)
-
CFRunLoopTimerRef:基於時間的觸發器.
-
CFRunLoopObserverRef: 觀察者,可以監聽RunLoop的狀態改變
-
CFRunLoopModeRef
-
CFRunLoopModeRef表明RunLoop運行模式
-
一個RunLoop對象包含若干個Mode(模式),每一個Mode又包含若干個 source/Timer/Observer
-
RunLoop運行時,只能指定一個Mode, 這個Mode又稱之爲CurrentMode,而後RunLoo就執行CurrentMode中的source/Timer/Observer
-
若是須要切換Mode,只能退出RunLoop,再從新指定一個Mode進入,這樣作是爲了分隔開不一樣組的Source/Timer/Observer,讓其不受影響
-
系統默認註冊了5個Mode:
-
NSDefaultRunLoopMode: App的默認Mode,一般主線程實在這個模式下運行
-
UITrackingRunLoopMode:界面跟蹤Mode,用於界面控件(ScrollView,tableView等等)追蹤觸摸滑動,保證界面滑動時不受其餘Mode影響
-
UIInitializationRunLoopMode:在剛啓動App是進入的第一個Mode,啓動完成後就再也不使用
-
GSEventReceiveRunLoopMode:接收系統事件的內部Mode,一般用不到
-
NSRunLoopCommonMode:這是一個佔位的Mode,不是一種真正的Mode,(能夠當作模式組,默認狀況下包括了NSDefaultRunLoopMode,UITrackingRunLoopMode)兩種模式.
-
CFRunLoopTimerRef
-
CFRunLoopSoruceRef
-
按照官方文檔,source的分類:
-
Port-Based Sources:基於端口的事件源:監聽程序響應的端口,基於端口事件是由系統內核自動發送的.
-
Custom Input Sources: 自定義輸入源:監聽自定義事件源,而自定義的輸入源是須要人工從其餘線程發送
-
Cocoa Perfrom Selector Source: selector事件源
-
按照源碼函數調用棧,source的分類:
-
Source0:非基於Prot(端口)的,是用戶主動觸發的事件
-
Source1:基於Prot(端口)的,經過內核和其餘線程相互發送消息
-
CFRunLoopObserverRef
-
RunLoop處理邏輯
-
若是RunLoop中沒有Timer或source,RunLoop就會馬上退出
-
每次運行RunLoop,RunLoop會自動處理以前未處理的消息,並通知相關觀察者.具體順序以下:
-
1.通知觀察者RunLoop已經啓動
-
2.通知觀察者即將開始啓動定時器
-
3.通知觀察者即將啓動非基於端口的事件源
-
4.啓動任何準備好的非基於端口的事件源
-
5.若是基於端口的事件源準備好並處於等待得狀態,當即啓動.並進入步驟9
-
6.通知觀察者線程進入休眠
-
7.將線程置於休眠直到任意下面的事件發生:
-
某一事件到達基於端口的源
-
定時器啓動
-
RunLoop設置的時間已經超時.(系統底層會給RunLoop設置一個超時時間,源碼中設置的是:9999999999.0)
-
RunLoop被手動喚醒
-
8.通知觀察者線程將被喚醒.
-
9.處理未處理的事件
-
若是用戶定義的定時器啓動,處理定時器事件並重啓RunLoop.進入步驟2
-
若是事件源啓動,傳遞相應的消息
-
若是RunLooop被顯示喚醒並且時間還沒超時,重啓RunLoop.進入步驟2
-
10.通知觀察者RunLoop結束.
-
如何讓子線程成爲常駐線程(讓一個子線程不進入消亡狀態,等待其餘線程發來消息,處理其餘事件)
原文連接:http://www.jianshu.com/p/94d61de9e139