1.什么是RunLoop
相當(dāng)于一個do-while循環(huán)的對象,在循環(huán)中處理各種事件來保持程序運(yùn)行,沒有事件處理時線程會休眠,在有事件時才會喚醒線程來處理连躏,節(jié)省CPU資源,提高效率贞滨。
一個線程對應(yīng)一個runloop對象入热,主線程的是系統(tǒng)創(chuàng)建,子線程的需要自己創(chuàng)建晓铆,在第一次獲取runloop時創(chuàng)建勺良,在線程結(jié)束時銷毀。
runloop保存在一個全局的dictionary里骄噪,key是線程尚困,value是runloop。
2.RunLoop Mode-運(yùn)行模式
做不同的事情會切換到不同的mode來執(zhí)行
NSDefaultRunLoopMode:默認(rèn)運(yùn)行mode链蕊,主線程一般在這個mode運(yùn)行事甜,當(dāng)用戶停止操作時候會在這個mode,沒有任務(wù)執(zhí)行了就會休眠示弓。
UITrackingRunLoopMode:界面跟蹤mode讳侨,用于scrollview追蹤滑動呵萨,保證界面滑動時不受其他mode影響奏属。
NSRunLoopCommonModes:占位mode,不是真正的運(yùn)行mode潮峦,會同時處理默認(rèn)mode和UImode的事件囱皿。
以上是實(shí)際開放的mode。
UIInitializationRunLoopMode:在剛啟動時第一個mode忱嘹,啟動完就不再使用了嘱腥。
GSEventReceiveRunLoopMode:接收系統(tǒng)事件的內(nèi)部mode,通常用不到拘悦。
3.RunLoop Source-事件源/輸入源
sources0:非基于mach_port的齿兔,一般為內(nèi)部的事件,如觸摸事件础米、selector事件分苇。
sources1:基于mach_port的內(nèi)核事件,可以由系統(tǒng)內(nèi)核或者其他進(jìn)程或者線程主動喚醒屁桑。
像點(diǎn)擊屏幕医寿,由source0進(jìn)行接收,分發(fā)到souces1處理蘑斧。
4.定時源:就是定時器靖秩,NSTimer
子線程定時器默認(rèn)不開啟须眷,如果在子線程中執(zhí)行需要手動開啟runloop。
timerWithTimeInterval是不加入到loop中沟突。
scheduledTimerWithTimeInterval會默認(rèn)加到默認(rèn)mode中花颗。
在滑動scrollview時會觸發(fā)UImode,需要將timer加入到UImode或者commonmode事扭,才能觸發(fā)捎稚。
5.RunLoop Observer-觀察者
監(jiān)聽runloop的狀態(tài)改變
6.RunLoop運(yùn)行邏輯
7.RunLoop實(shí)際應(yīng)用
a、autoreleasepool自動釋放池
在主線程的runloop里注冊了兩個observer求橄,即將進(jìn)入(Entry)loop時創(chuàng)建_objc_autoreleasePoolPush()今野,優(yōu)先級最高;在即將休眠(BeforeWaiting)時會釋放舊池并創(chuàng)建新池_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()罐农,即將退出(Exit)loop時會釋放池子_objc_autoreleasePoolPop()条霜,優(yōu)先級最低。
b涵亏、更新UI
在mainloolp中即將休眠(BeforeWaiting)和即將退出(Exit)注冊宰睡,會檢查setNeedDisplay判斷視圖是否需要更新,所以更新UI需要在主線程中气筋。
c拆内、線程保活
NSCondition條件鎖宠默,當(dāng)有任務(wù)時喚醒線程來處理麸恍。
利用runloop保活:
runloop開啟方式:
d搀矫、監(jiān)聽優(yōu)化系統(tǒng)卡頓
1)當(dāng)runloop長時間停在kCFRunLoopBeforeSources抹沪,導(dǎo)致無法休眠,或者停在kCFRunLoopAfterWaiting瓤球,在喚醒后接受時間太長融欧,就可以認(rèn)為是卡頓。
2)注冊觀察者卦羡,并添加到主線程的commonmode中噪馏,觀察runloop的所有狀態(tài),設(shè)置回調(diào)函數(shù)
3)設(shè)置信號量為0绿饵,如果<0則會阻塞當(dāng)前線程欠肾,在子線程使用wait阻塞線程,并設(shè)置超時時間蝴罪,超時會signal繼續(xù)執(zhí)行線程董济,或者收到主線程的消息,也會signal
4)當(dāng)長時間被阻塞要门,查看是否在beforesources或者afterwaiting狀態(tài)并且超時了虏肾,記為卡頓廓啊。