1.RunLoop是一種機(jī)制 : 讓線程結(jié)束時不關(guān)閉,而是進(jìn)入休眠狀態(tài)等待喚醒.讓線程能隨時處理事件但并不退出.
2.RunLoop 實(shí)際上就是一個對象,這個對象管理了其需要處理的事件和消息,并提供了一個入口函數(shù)來執(zhí)行上面 Event Loop(do-while) 的邏輯,線程執(zhí)行了這個函數(shù)后,就會一直處于這個函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中,直到這個循環(huán)結(jié)束(比如傳入 quit 的消息),函數(shù)返回。
3.OSX/iOS 系統(tǒng)中,提供了兩個這樣的對象:NSRunLoop 和 CFRunLooPRef。
CFRunLoopRef 是 CoreFoundation框架的 提供了純C代碼的API,這些API是線程安全的
而NSRunloop是基于CFRunLoopRef的二次封裝,這些API不是線程安全的
4.Runloop不能自己創(chuàng)建,但是可以在線程中獲得(主線程自動開啟RunLoop)
蘋果不允許直接創(chuàng)建 RunLoop,它只提供了兩個自動獲取的函數(shù):CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。
線程和 RunLoop 之間是一一對應(yīng)的,其關(guān)系是保存在一個全局的 Dictionary 里。線程剛創(chuàng)建時并沒有 RunLoop,如果你不主動獲取,那它一直都不會有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時,RunLoop 的銷毀是發(fā)生在線程結(jié)束時。你只能在一個線程的內(nèi)部獲取其 RunLoop(主線程除外)。
每一個RunLoop對應(yīng)一個線程。每一個線程都可以擁有一個RunLoop,這也就是說線程可以創(chuàng)建一個屬于自己的Runloop,也可以不創(chuàng)建自己的RunLoop。這都是根據(jù)程序內(nèi)部的需求來決定的。這里需要注意的是:你創(chuàng)建一個runLoop但是你還必須要手動的讓其run。
5.runloop和定時器
NSTimer 其實(shí)就是 CFRunLoopTimerRef,他們之間是 toll-free bridged 的。一個 NSTimer 注冊到 RunLoop 后,RunLoop 會為其重復(fù)的時間點(diǎn)注冊好事件.
例如 10:00, 10:10, 10:20 這幾個時間點(diǎn)。RunLoop為了節(jié)省資源,并不會在非常準(zhǔn)確的時間點(diǎn)回調(diào)這個Timer。Timer 有個屬性叫做 Tolerance (寬容度),標(biāo)示了當(dāng)時間點(diǎn)到后,容許有多少最大誤差。
如果某個時間點(diǎn)被錯過了,例如執(zhí)行了一個很長的任務(wù),則那個時間點(diǎn)的回調(diào)也會跳過去,不會延后執(zhí)行。就比如等公交,如果 10:10 時我忙著玩手機(jī)錯過了那個點(diǎn)的公交,那我只能等 10:20 這一趟了。
CADisplayLink 是一個和屏幕刷新率一致的定時器(但實(shí)際實(shí)現(xiàn)原理更復(fù)雜,和 NSTimer 并不一樣,其內(nèi)部實(shí)際是操作了一個 Source)。如果在兩次屏幕刷新之間執(zhí)行了一個長任務(wù),那其中就會有一幀被跳過去(和 NSTimer 相似),造成界面卡頓的感覺。在快速滑動TableView時,即使一幀的卡頓也會讓用戶有所察覺。Facebook 開源的 AsyncDisplayLink 就是為了解決界面卡頓的問題,其內(nèi)部也用到了 RunLoop
6.PerformSelecter
當(dāng)調(diào)用 NSObject 的 performSelecter:afterDelay: 后,實(shí)際上其內(nèi)部會創(chuàng)建一個 Timer 并添加到當(dāng)前線程的 RunLoop 中。所以如果當(dāng)前線程沒有 RunLoop,則這個方法會失效。
當(dāng)調(diào)用 performSelector:onThread: 時,實(shí)際上其會創(chuàng)建一個 Timer 加到對應(yīng)的線程去,同樣的,如果對應(yīng)線程沒有 RunLoop 該方法也會失效。
文章借鑒:http://www.cocoachina.com/ios/20150601/11970.html新聞熱點(diǎn)
疑難解答