深入理解 [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]

最近在看線(xiàn)程?;睿l(fā)現(xiàn)了這個(gè)函數(shù)無(wú)法理解,根本原因還是這個(gè)函數(shù)的蘋(píng)果文檔沒(méi)有深入理解,然后沒(méi)有多做嘗試。

先說(shuō)結(jié)論,再說(shuō)過(guò)程。
結(jié)論:1)runMode:beforeDate只是執(zhí)行一次runloop循環(huán),處理完第一次input source內(nèi)容,就會(huì)結(jié)束該runloop。注:第一次的input source內(nèi)容要有活干,才算第一次。2)timer不能算input source,比較特殊,文檔里有說(shuō)明,你會(huì)發(fā)現(xiàn)timer能正常運(yùn)作。直到第一次input source出現(xiàn)才會(huì)停止runloop


該函數(shù)對(duì)應(yīng)的蘋(píng)果文檔:

Demo1:為了驗(yàn)證run是啟動(dòng)一直跑,常駐。

thread中開(kāi)啟監(jiān)聽(tīng),加入port,執(zhí)行run


用戶(hù)點(diǎn)擊屏幕操作,會(huì)怎么執(zhí)行


啟動(dòng)后,為了啟動(dòng)runloop而加入的port沒(méi)活干,直接發(fā)出32休眠通知。
用戶(hù)點(diǎn)擊屏幕,runloop開(kāi)始處理source0

每次用戶(hù)點(diǎn)擊,都會(huì)進(jìn)入一次runloop循環(huán),但是直接是到達(dá)退出runloop狀態(tài),然后緊接著再進(jìn)入。run的本質(zhì)是不斷執(zhí)行runMode:。

Demo2:為了驗(yàn)證runMode只運(yùn)行一次
其余不變,將[[NSRunLoop currentRunLoop] run];
改為[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

啟動(dòng)和run效果一樣,但是runMode的文檔是?“it returns after either the first input source is processed or?limitDate?is reached“。處理第一次的input source后就會(huì)返回,那么port也算第一次,但是是個(gè)沒(méi)有任務(wù)的第一次(后面會(huì)做個(gè)實(shí)驗(yàn),加入的是有任務(wù)的第一次,在看點(diǎn)擊屏幕是否還會(huì)觸發(fā)),提前結(jié)論:根據(jù)實(shí)驗(yàn),應(yīng)該是需要“有活干的第一次”才會(huì)停下來(lái)runloop。
緊接著點(diǎn)擊屏幕:

執(zhí)行完一次source0點(diǎn)擊屏幕,runloop就結(jié)束了。
再次點(diǎn)擊,會(huì)出現(xiàn)崩潰。該線(xiàn)程已經(jīng)結(jié)束,不再執(zhí)行任務(wù)。報(bào)錯(cuò)是EXC_BAD_ACCESS。本質(zhì)就是該塊內(nèi)存已經(jīng)不能再執(zhí)行所發(fā)出的指令了。

延伸:如果把?[self performSelector:@selector(tttt) onThread:self.testThread withObject:nil waitUntilDone:YES];換成
?[self performSelector:@selector(tttt) onThread:self.testThread withObject:nil waitUntilDone:NO];就不會(huì)崩潰。
YES的含義是一直等到執(zhí)行完畢再往下執(zhí)行;NO的含義是不用等執(zhí)行完畢繼續(xù)往下執(zhí)行。

Demo3:也是為了驗(yàn)證runloop只跑一次循環(huán)

兩個(gè)performSelector...waitUntilDone:NO都執(zhí)行了。

一個(gè)performSelector...waitUntilDone:YES;一個(gè)performSelector...waitUntilDone:NO,只執(zhí)行第一句,因?yàn)橐鹊谝粋€(gè)執(zhí)行完,執(zhí)行完runloop一次循環(huán)就結(jié)束了。不再執(zhí)行第二個(gè)input source了。當(dāng)然,此處再點(diǎn)擊一次就是崩潰。因?yàn)閜erform到一個(gè)已經(jīng)結(jié)束的線(xiàn)程上了。

Demo4:runMode只執(zhí)行一次,第一次加入的任務(wù)有活干,再點(diǎn)擊就無(wú)反應(yīng)了。

如果在runMode前加入performSelector...waitUntilDone:NO,則是在runloop中執(zhí)行

如果在runMode前加入performSelector...waitUntilDone:YES,則執(zhí)行完再往下走,相當(dāng)于runloop中是空內(nèi)容,無(wú)法啟動(dòng)runloop。perform的任務(wù)是沒(méi)有在runloop中執(zhí)行的。

Demo5:在runloop中加入timer,timer比較特殊

關(guān)于timer的小知識(shí)點(diǎn):
scheduledTimerWithTimeInterval生成的timer =?timerWithTimeInterval+[NSRunLoop currentRunLoop] addTimer...]生成的timer。

runMode方法根據(jù)文檔:

timer會(huì)在等待這個(gè)方法返回時(shí),觸發(fā)很多次。不被認(rèn)為是一種input source。
最后,簡(jiǎn)單提一嘴通過(guò)runloop檢測(cè)卡頓原理:2和64是檢測(cè)卡頓狀態(tài),根據(jù)狀態(tài)的變化間隔。后面再細(xì)聊~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容