如果對(duì)Runloop基本概念不清楚的,可以先移步ibireme的這篇詳細(xì)的博文:深入理解RunLoop
這篇文章想更深入研究的一個(gè)問題是:
我們常用延遲調(diào)用函數(shù)的方法 :PerformSelector、 NSTimer奸鬓、Dispatch_Main_Queue
位隶,在任務(wù)被加入到RunLoop后被執(zhí)行的順序究竟是如何的串纺?
首先羡疗,閱讀下RunLoop的源碼后摆霉,可以得知RunLoop每跑一次循環(huán)會(huì)按優(yōu)先級(jí)處理各個(gè)隊(duì)列里的任務(wù), 處理順序依次為:
Source0-> Source1-> (Timer=Dispatch_Main_Queue)
那么NSTimer和Dispatch_Main_Queue很容易對(duì)應(yīng)上后面的兩個(gè)隊(duì)列豪椿,剩下的就是比較有意思的PerformSelector這個(gè)方法奔坟。
對(duì)PerformSelector的調(diào)用打個(gè)斷點(diǎn),發(fā)現(xiàn)PerformSelector是同步調(diào)用的搭盾。并不會(huì)schedule到Runloop中去咳秉。
那如果是調(diào)用PerformSelectorAfterDelay的方法是什么情況呢?
我們直接看堆棧:
可以看到鸯隅,如果是afterDelay的方法其實(shí)是Timer的回調(diào)里實(shí)現(xiàn)的澜建,哪怕Delay的時(shí)間你設(shè)置為0。
那我們?cè)倏匆幌轮苯邮褂肗STimer調(diào)用的堆棧:
OK蝌以, 都是在__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__中處理炕舵,試著調(diào)整下兩次調(diào)用的相對(duì)順序,發(fā)現(xiàn)函數(shù)被調(diào)用的順序也會(huì)相應(yīng)變化饼灿。
再試著調(diào)整下PerformSelector幕侠、NSTimer、Dispatch_Main_Queue的調(diào)用位置碍彭,發(fā)現(xiàn)其執(zhí)行順序是不會(huì)改變的晤硕。
綜上所示,我們可以得出一下幾點(diǎn)結(jié)論:
1. RunLoop內(nèi)執(zhí)行的優(yōu)先級(jí)庇忌,PerformSelector(同步)>(NSTimer=PerformSelectorAfterDelay=Dispatch_Main_Queue)
2.?PerformSelectorAfterDelay和NSTimer一樣都是在Timer隊(duì)列中處理舞箍,按照進(jìn)入隊(duì)列的次序依次執(zhí)行
補(bǔ)充下,除了以上常用的方法外皆疹,還有一個(gè)CFRunLoopPerformBlock可以插入任務(wù)到Runloop中疏橄,該任務(wù)在處理source0之前和處理完timer和Dispatch_Main_Queue會(huì)被分別調(diào)用一次。
對(duì)應(yīng)的是__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__