iOS RunLoop

HUA YU TSENG
3 min readFeb 27, 2020

一種使線程能一直接收與分發相對應事件的機制,如UI更新、TouchEvent、Timer、selector。

大致可區分為 common mode & private mode

CommonMode :
1. kCFRunLoopDefaultMode: 預設Mode通常主線程在此Mode下運行
2. UITrackingRunLoopMode: UI追蹤,如 ScrollView 的觸摸滑動等等
3. kCFRunLoopCommonModes: 此mode用以標記上述兩個mode,嚴格來說不算是mode
PrivateMode:
1. UIInitializationRunLoopMode: 用於啟動APP,基本上APP啟動後就不在使用
2. GSEventReceiveRunLoopMode: 屬於GraphicsServices,像是音量鍵

當我們設定一個Timer時,在預設狀況下,這個Timer會在 NSDefaultRunLoopMode 也就是RunLoop.Mode.default

問題來了,當畫面中的ScrollView觸發滑動手勢時,此時Mode會切換到UITrackingRunLoopMode 也就是RunLoop.Mode.tracking,由於Mode轉換了,處於NSDefaultRunLoopMode的Timer也就跟著被暫停了,解決方法如下,只要將Timer運行的Mode改為common,如此Timer就可以同時在kCFRunLoopDefaultMode與UITrackingRunLoopMode運行。

var sparkTimer = Timer() {
didSet {
RunLoop.current.add(sparkTimer, forMode: .common)
}
}

有些情境可以反過來運用,例如只有當滑動手勢出發時才要執行某個Timer,可以將Timer設定在UITrackingRunLoopMode,如此一來這個Timer只有在UITrackingRunLoopMode下才會運作。

var UITrackingTimer = Timer() {
didSet {
RunLoop.current.add(sparkTimer, forMode: .tracking)
}
}

--

--

HUA YU TSENG

I am Red, an iOS developer, I have hands on experience in iOS, Flutter, familiar with RxSwift Moya Unit/UI testing and Gitlab-CI.