什么是 Runloop?
- 從字面上講就是運行循環。
- 它內部就是do-while循環,在這個循環內部不斷地處理各種任務。說通俗來說就是一個死循環.
- 一個線程對應一個RunLoop,主線程的RunLoop默認已經啟動,子線程的RunLoop得手動啟動(調用run方法)
-
RunLoop只能選擇一個Mode啟動,如果當前Mode中沒有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop
-
基本的作用就是保持程序的持續運行,處理app中的各種事件。通過runloop,有事運行,沒事就休息,可以節省cpu資源,提高程序性能。
Runloop 初識
首先我們知道新建一個項目之后他的啟動是Main函數,那么我們首先往UIApplicationMain函數的前后分別加入一行NSlog,如下圖
運行之后我們看到,控制台只輸出了 "這里" 並沒有輸入"here",這是因為在UIApplicationMain上開啟了主線程的Runloop循環,也就是說在那里有一個死循環,所以下邊的"here"不會輸出.那么問題來了,為什么要開啟這個Runloop循環,開啟這個循環有什么用?
1,保證主線程的生命,保證當前線程不退出,這是必不可缺少的一部分,如果程序一運行,主線程沒了,UIKit都沒了那就沒必要繼續開發了....
2,負責監聽事件,網絡事件,觸摸事件時鍾等等.
Runloop 入門
經常會有人在面試中被問到:NStimer准嗎?談談你的看法?如果不准該怎樣實現一個精確的NSTimer? 實際上面試官是在看你懂不懂Runloop.
這時候你該這樣回答:
1,無論是單次執行的NSTimer
還是重復執行的NSTimer
都不是准時的
2這與當前NSTimer
所處的線程有很大的關系,如果NSTimer
當前所處的線程正在進行大數據處理(假設為一個大循環),NSTimer
本次執行會等到這個大數據處理完畢之后才會繼續執行。這期間有可能會錯過很多次NSTimer
的循環周期,但是NSTimer
並不會將前面錯過的執行次數在后面都執行一遍,而是繼續執行后面的循環,也就是在一個循環周期內只會執行一次循環。
所以我們要習慣把NSTimer放在Runloop中去執行, [NSRunLoop currentRunLoop];//獲取當前線程的Runloop [NSRunLoop mainRunLoop];//獲取主線程的Runloop 見下圖
這里需要注意的是forMode 提供的參數.我們根據實例來了解這個mode到底有什么用,首先往屏幕上放一個textView,運行程序后,控制器在不停的運行timer(也就是不停的去執行Method方法). 但是當我們拖拽textView的時候,Metiod方法停止運行了,相信大家在平時開發中也遇到過這樣的情況,那么這是為什么呢?
答:記住一條規則,Runloop處理事件的時候,UI優先,天大地大UI最大. (這就合理的解釋了為什么當我們拖動textView的時候timer方法不執行了)這也是一種NSTimer不准的情況
那么怎么在拖動的時候使timer方法繼續執行呢?除了GCD之外我們了解一下Runloop.
上圖我們看到forMode是NSDefault模式的,也就是默認模式的,mode一共有五種,我們只需要知道其中三種即可
- NSDefalutRunLoopMode 默認狀態.優先處理UI模式下的事件
- UITrackingRunLoopMode UI模式,將timer放在UI模式下,但是當停止拖拽textView時,timer方法停止了.(只能被UI事件喚醒)
- NSRunLoopCommonModes 默認包括上面兩種,也就是說,兼容兩種的,也是通用的.
到這里我們就解決了這一問題,在這給大家科普一條,UI為什么要放在主線程執行,我們開發的項目首先要用戶體驗好,如果不在主線程中(不優先),那么它就會涉及到資源搶奪,我們還要給他上鎖為了安全性,但是上鎖又會影響性能,那么我們的用戶體驗將會特別差.所以UI操作永遠不會涉及到多線程.所以UIKit要放在主線程上.
還有一個誤區,很多人說,主線程沒有了,子線程就沒了,整個程序就沒了.當然對於用戶來說,主線程沒了整個項目就沒了,因為UI不動了.但對於開發者來說,主線程沒了,子線程不一定沒了.相對於系統來說,主線程也只是一條子線程而已.下邊附案例.
viewdidload中開辟子線程,將定時器放在子線程中,當點擊屏幕時退出主線程.此時看控制台,子線程沒有掛,還在輸出. 只是UI不動了.所以當你面試的時候不要說主線程沒了子線程也不會有這種話.
新手分享!!!他說:想要成為大牛,首先要學會分享,把你學到的東西分享給別人,利己利人.如果你學到東西了,那把它分享給你身邊的朋友吧.