一巍举、特性
- iOS中所有的事件監(jiān)聽全部是由Runloop負責(zé)監(jiān)聽的脆荷,main線程的Runloop在應(yīng)用啟動的時候就會自動創(chuàng)建,其他子線程需要自己啟動,不會自己創(chuàng)建Runloop
- 線程和Runloop之間是一一對用的蜓谋,其關(guān)系是保存在一個全局的字典里面苔严,線程剛創(chuàng)建時,并沒有Runloop孤澎,不主動獲取,那么它一直不會有欠窒,Runloop的創(chuàng)建發(fā)生在第一次獲取時覆旭。
- Runloop并不是線程安全,所以需要避免在其他線程上調(diào)用當前線程的Runloop
- Runloop負責(zé)管理autorelease pools岖妄,負責(zé)處理消息事件型将,如輸入源事件、計時器事件荐虐,網(wǎng)絡(luò)請求等
- 通Runloop機制實現(xiàn)省電七兜,流暢、響應(yīng)速度快福扬。用戶體驗好
二腕铸、Runloop Mode
蘋果文檔中提到的 Mode 有五個:
- NSDefaultRunLoopMode:App默認的Model,主線程是在這個Model下運行的
- NSConnectionReplyMode:該模式用來監(jiān)控NSConnection對象铛碑。你通常不需要在你的代碼中使用該模式(ios9.0已經(jīng)廢棄NSConnection了狠裹,由NSURLSession替代,所以這個應(yīng)該然并卵了吧)
- NSModalPanelRunLoopMode: 使用該模式來標識用于modal panel(模態(tài)面板)的事件汽烦。
- NSEventTrackingRunLoopMode:界面跟蹤Mode涛菠,用于ScrollView追蹤觸摸滑動,保證界面滑動時不受其他Mode影響撇吞。 (當我們滑動ScrollView,TableView等繼承于ScrollView的控件是, 系統(tǒng)會切換模式為: UITrackingRunLoopMode, 跟蹤你的觸摸事件, 當停止?jié)L動的時候, 系統(tǒng)會切換模式為: kCFRunLoopDefaultMode)俗冻,
- NSRunLoopCommonModes 這是一組可配置的通用模式。將input sources與該模式關(guān)聯(lián)則同時也將input sources與該組中的其它模式進行了關(guān)聯(lián)牍颈。對于Cocoa應(yīng)用迄薄,該模式缺省的包含了default,modal以及event tracking模式煮岁。
iOS公開出來的只有兩個:
一個常見的問題就是噪奄,主線程中一個NSTimer添加在default mode中,當界面上有一些scroll view的滾動頻繁發(fā)生導(dǎo)致run loop運行在UItraking mode中人乓,從而這個timer沒能如期望那般的運行勤篮。所以,我們就可以把這個timer加到NSRunLoopCommonModes中來解決
舉個栗子: 如果有TableView上有輪播圖(NSTimer), 則在滾動TableView的時候,定時器是不好使的, 因為添加定時器默認是在kCFRunLoopDefaultMode下的
三色罚、Runloop 應(yīng)用
如果我們將定時器放到UITrackingRunLoopMode
模式下, 則只有在拖動的時候,定時器才可以工作, 代碼如下:
// 調(diào)用了scheduledTimer返回的NSTimer的定時器對象,已經(jīng)被自動添加到當前的runLoop中(一個線程對應(yīng)一個runloop,如果在子線程中添加定時器..添加到子線程的runloop中),默認為NSDefaultRunLoopMode模式
let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(printAction), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: .UITrackingRunLoopMode)
// 如果需要更改模式, 直接這樣就可以
RunLoop.current.add(timer, forMode: .commonModes)```
iOS 10 加入新閉包形式的寫法碰缔,
// NSDefaultRunLoopMode:NSTimer只有在默認模式下(NSDefaultRunLoopMode)工作,切換到其他模式不再工作戳护,比如拖拽了界面上的某個控件(會切換成UITrackingRunLoopMode)
let timer = Timer.init(timeInterval: 1, repeats: true) { (timer) in
print("新timer執(zhí)行了")
}
RunLoop.current.add(timer, forMode: .defaultRunLoopMode)```
CADisplayLink如果NSTimer一樣, 也是添加到模式中