製作一個好的App有非常多因素,而其中使用者體驗非常重要,影響用戶是否會繼續使用我們的App。
原本以為Timer會固定時間就觸發,然而在多線程的狀況下並不是如此,因為每個事件都會被排程,假如前面執行事件會花長時間,就會影響原本我們預定時機點想觸發的Timer。
目前遇到的狀況:
手指滑動TableView,原本每秒執行的Timer卻不運作,直到放開手指。
原來把Timer加入到RunLoop就能解決問題!
程式碼這麼寫:
timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
果真它就如預期運行了!
接下來由高手解釋什麼是NSRunLoop?
NSRunLoop是消息機制的處理模式
NSRunLoop的作用在於有事情做的時候使的當前NSRunLoop的線程工作,沒有事情做讓當前NSRunLoop的線程休眠。
NSTimer默認添加到當前NSRunLoop中,也可以手動制定添加到自己新建的NSRunLoop。
NSRunLoop就是一直在循環檢測,從線程start到線程end,檢測inputsource(如點擊,雙擊等操作)同步事件,檢測timesource同步事件,檢測到輸入源會執行處理函數,首先會產生通知,corefunction向線程添加runloop observers來監聽事件,意在監聽事件發生時來做處理。
在單線程的app中,不需要注意Run Loop,但不代表沒有。程序啟動時,系統已經在主線程中加入了Run Loop。它保證了我們的主線程在運行起來後,就處於一種「等待」的狀態(而不像一些命令行程序一樣運行一次就結束了),這個時候如果有接收到的事件(Timer的定時到了或是其他線程的消息),就會執行任務,否則就處於休眠狀態。
runloopmode是一個集合,包括監聽:事件源,定時器,以及需通知的runloop observers。
模式包括:
- default模式:幾乎包括所有輸入源(除NSConnection) NSDefaultRunLoopMode模式
- mode模式:處理modal panels
- connection模式:處理NSConnection事件,屬於系統內部,用戶基本不用
- event tracking模式:如組件拖動輸入源UITrackingRunLoopModes 不處理定時事件
- common modes模式:NSRunLoopCommonModes 這是一組可配置的通用模式。將input sources與該模式關聯則同時也將input sources與該組中的其它模式進行了關聯。
每次運行一個run loop,你指定(顯式或隱式)run loop的運行模式。當相應的模式傳遞給run loop時,只有與該模式對應的input sources才被監控並允許run loop對事件進行處理(與此類似,也只有與該模式對應的observers才會被通知)
例:
- 在timer與table同時執行情況,當拖動table時,runloop進入UITrackingRunLoopModes模式下,不會處理定時事件,此時timer不能處理,所以此時將timer加入到NSRunLoopCommonModes模式(addTimer forMode)。
- 在scroll一個頁面時來鬆開,此時connection不會收到消息,由於scroll時runloop為UITrackingRunLoopModes模式,不接收輸入源,此時要修改connection的mode。
隨意留個言吧:)~