一帖蔓、什么是runloop
顧名思義就是運(yùn)行循環(huán)丘侠,在程序運(yùn)行過程中循環(huán)做一些事情
二、runloop的基本作用
1炼杖、保持程序的持續(xù)運(yùn)行
2灭返、處理App中的各種事件(比如觸摸事件、定時(shí)器事件等)
3坤邪、節(jié)省CPU資源熙含,提高程序性能:該做事時(shí)做事,該休息時(shí)休息
......
三艇纺、應(yīng)用范疇
1怎静、定時(shí)器(Timer)、PerformSelector
2黔衡、GCD Async Main Queue
3蚓聘、事件響應(yīng)、手勢(shì)識(shí)別盟劫、界面刷新
4夜牡、網(wǎng)絡(luò)請(qǐng)求
5、AutoreleasePool
......
四侣签、獲取runloop對(duì)象
1氯材、OC方法
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象
2、C語言方法
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對(duì)象
CFRunLoopGetMain(); // 獲得主線程的RunLoop對(duì)象
五硝岗、RunLoop相關(guān)的類
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
CFRunLoopRef
內(nèi)部底層結(jié)構(gòu)
typedef struct __CFRunloop * CFRunLoopRef;
struct __CFRunloop{
pthread_ _t_ pthread;//線程
CFMutableSetRef_ commonModes ;
CFMutableSetRef_ commonModeItems ;
CFRunLoopModeRef_ currentMode ;//當(dāng)前模式
CFMutableSetRef_ modes;//模式數(shù)組(里面存放好多模式 模式類型為CFRunLoopModeRef)
}
CFRunLoopModeRef
內(nèi)部底層結(jié)構(gòu)
typedef struct__ CFRunLoopMode *CFRunLoopModeRef ;
struct __CFRunLoopMode{
CFStringRef _name ;//模式名稱
CFMutableSetRef _ sources0; (內(nèi)部存放CFRunLoopSourceRef 類型的對(duì)象 )
CFMutableSetRef _ sources1 ;(內(nèi)部存放CFRunLoopSourceRef 類型的對(duì)象 )
CFMutableArrayRef _ observers;(內(nèi)部存放CFRunLoopObserverRef 類型的對(duì)象 )
CFMutableArrayRef _ timers;(內(nèi)部存放CFRunLoopTimerRef 類型的對(duì)象 )
}
相關(guān)說明
1、CFRunLoopModeRef代表RunLoop的運(yùn)行模式
2袋毙、一個(gè)RunLoop包含若干個(gè)Mode型檀,每個(gè)Mode又包含若干Source0/Source1/Timer/Observer
3、RunLoop啟動(dòng)時(shí)只能選擇其中一個(gè)Mode听盖,作為currentMode
4胀溺、如果需要切換Mode,只能退出當(dāng)前mode皆看,再重新選擇一個(gè)Mode進(jìn)入仓坞,
(作用: 不同組的Source0/Source1/Timer/Observer能分隔開來,互不影響)
5腰吟、如果Mode里沒有任何Source0/Source1/Timer/Observer无埃,RunLoop會(huì)立馬退出
常見的2種Mode
1、kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認(rèn)Mode毛雇,通常主線程是在這個(gè)Mode下運(yùn)行
2嫉称、UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng)灵疮,保證界面滑動(dòng)時(shí)不受其他 Mode 影響
CFRunLoopObserverRef
/* Run Loop Observer Activities */
typedef CF_ OPTIONS (CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0) , //即將進(jìn)入Loop
kCFRunLoopBeforeTimers = (1UL << 1)织阅, // 即將處理Timer
kCFRunLoopBeforeSources = (1UL << 2) , //即將處理Source
kCFRunLoopBeforeWaiting = (1UL << 5) , // 即將進(jìn)入休眠 ,
kCFRunLoopAfterWaiting = (1UL << 6) , / /剛從休眠中喚醒
kCFRunLoopExit = (1UL << 7)震捣, //即將退出Loop
kCFRunL oopAllActivities = 0x0FFFFFFFU //所有狀態(tài)集合
};
我們可以利用 CFRunLoopObserverRef 來監(jiān)聽runloop 的各種狀態(tài):(如刷新UI等等)
// 創(chuàng)建Observer
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
switch (activity) {
case kCFRunLoopEntry: {
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
NSLog(@"kCFRunLoopEntry - %@", mode);
CFRelease(mode);
break;
}
case kCFRunLoopExit: {
CFRunLoopMode mode = CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());
NSLog(@"kCFRunLoopExit - %@", mode);
CFRelease(mode);
break;
}
default:
break;
}
});
// 添加Observer到RunLoop中
CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
// 釋放
CFRelease(observer);
六荔棉、RunLoop的運(yùn)行邏輯
Source0 作用
1闹炉、觸摸事件處理
2、performSelector:onThread:
Source1 作用
1润樱、基于Port的線程間通信
2渣触、系統(tǒng)事件捕捉
Timers 作用
1、NSTimer
2祥国、performSelector:withObject:afterDelay:
Observers 作用
1昵观、用于監(jiān)聽RunLoop的狀態(tài)
根據(jù)runloop的狀態(tài)來做相應(yīng)的事情 如:UI刷新(BeforeWaiting)、Autorelease pool(BeforeWaiting)等
流程
01舌稀、通知Observers:進(jìn)入Loop
02啊犬、通知Observers:即將處理Timers
03、通知Observers:即將處理Sources
04壁查、處理Blocks
05觉至、處理Source0(可能會(huì)再次處理Blocks)
06、如果存在Source1睡腿,就跳轉(zhuǎn)到第8步
07语御、通知Observers:開始休眠(等待消息喚醒)
08、通知Observers:結(jié)束休眠(被某個(gè)消息喚醒)
01> 處理Timer
02> 處理GCD Async To Main Queue
03> 處理Source1
09席怪、處理Blocks
10应闯、根據(jù)前面的執(zhí)行結(jié)果,決定如何操作
01> 回到第02步
02> 退出Loop
11挂捻、通知Observers:退出Loop
七碉纺、runloop與線程之間的關(guān)系
1、每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
2刻撒、RunLoop保存在一個(gè)全局的Dictionary里骨田,線程作為key,RunLoop作為value
3声怔、線程剛創(chuàng)建時(shí)并沒有RunLoop對(duì)象态贤,RunLoop會(huì)在第一次獲取它時(shí)創(chuàng)建([NSRunLoop currentRunLoop])
4、RunLoop會(huì)在線程結(jié)束時(shí)銷毀
5醋火、主線程的RunLoop已經(jīng)自動(dòng)獲扔破(創(chuàng)建),子線程默認(rèn)沒有開啟RunLoop
面試題1芥驳、講講 RunLoop介粘,項(xiàng)目中有用到嗎?
答:肯定是有用到的 例如下
1晚树、控制線程生命周期(線程币霾桑活)
2、解決NSTimer在滑動(dòng)時(shí)停止工作的問題
3、監(jiān)控應(yīng)用卡頓
4慨亲、性能優(yōu)化
面試題2婚瓜、runloop內(nèi)部實(shí)現(xiàn)邏輯?
第一步:首先通知Observers進(jìn)入Loop 然后處理一些 定時(shí)器刑棵、事件巴刻、block
第二步:事件處理完成之后通知Observers進(jìn)入休眠狀態(tài)開始休眠 等待消息喚醒
第三步:通知Observers結(jié)束休眠處理一些 定時(shí)器、事件蛉签、block
面試題3胡陪、runloop和線程的關(guān)系?
一對(duì)一關(guān)系
1碍舍、每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
2柠座、RunLoop保存在一個(gè)全局的Dictionary里,線程作為key片橡,RunLoop作為value
3妈经、線程剛創(chuàng)建時(shí)并沒有RunLoop對(duì)象,RunLoop會(huì)在第一次獲取它時(shí)創(chuàng)建([NSRunLoop currentRunLoop])
4捧书、RunLoop會(huì)在線程結(jié)束時(shí)銷毀
5吹泡、主線程的RunLoop已經(jīng)自動(dòng)獲取(創(chuàng)建)经瓷,子線程默認(rèn)沒有開啟RunLoop
面試題4爆哑、timer 與 runloop 的關(guān)系?
一個(gè)runloop下會(huì)包含很多個(gè)model,每個(gè)model下又會(huì)包含很多的timer/source/observe舆吮,同一時(shí)刻runloop只能在一種模式下運(yùn)行泪漂,處理一種模式下的狀態(tài)
所以層次關(guān)系是 runloop 包含 model 包含 timer/source/observe
面試題5、程序中添加每3秒響應(yīng)一次的NSTimer歪泳,當(dāng)拖動(dòng)tableview時(shí)timer可能無法響應(yīng)要怎么解決?
runloop 常用的mode有兩種 :NSDefaultRunLoopMode露筒、UITrackingRunLoopMode
程序默認(rèn)處于 NSDefaultRunLoopMode 模式下 但是頁面滑動(dòng)的時(shí)候 runloop的模式就會(huì)切換到 UITrackingRunLoopMode 此時(shí)就會(huì)退出 NSDefaultRunLoopMode 呐伞,在NSDefaultRunLoopMode模式下所有的操作都會(huì)被停止(如:NSTimer事件響應(yīng))。當(dāng)頁面停止滑動(dòng)時(shí) 就會(huì)自動(dòng)切換到NSDefaultRunLoopMode慎式,(此時(shí)NSTimer才會(huì)繼續(xù)工作 )
因此:想要在當(dāng)拖動(dòng)tableview時(shí)timer繼續(xù)工作 就必須把 timer 添加到runloop任何模式都能工作伶氢。代碼如下
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSRunLoopCommonModes:并不是一個(gè)真的模式,它只是一個(gè)標(biāo)記
面試題6瘪吏、runloop 是怎么響應(yīng)用戶操作的癣防, 具體流程是什么樣的?
首先由Source1捕捉系統(tǒng)事件 然后Source1又將事件存放在 事件隊(duì)列中交給Source0來處理掌眠。
面試題7蕾盯、說說runLoop的幾種狀態(tài)
一共有6中狀態(tài):
1、kCFRunLoopEntry = (1UL << 0) , //即將進(jìn)入Loop
2蓝丙、kCFRunLoopBeforeTimers = (1UL << 1)级遭, // 即將處理Timer
3望拖、kCFRunLoopBeforeSources = (1UL << 2) , //即將處理Source
4、kCFRunLoopBeforeWaiting = (1UL << 5) , // 即將進(jìn)入休眠 挫鸽,
5说敏、kCFRunLoopAfterWaiting = (1UL << 6) , / /剛從休眠中喚醒
6、kCFRunLoopExit = (1UL << 7)丢郊, //即將退出Loop
面試題8盔沫、runloop的mode作用是什么?
常見的mode有兩種 NSDefaultRunLoopMode和UITrackingRunLoopMode
1枫匾、kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認(rèn)Mode架诞,通常主線程是在這個(gè)Mode下運(yùn)行
2、UITrackingRunLoopMode:界面跟蹤 Mode婿牍,用于 ScrollView 追蹤觸摸滑動(dòng)侈贷,保證界面滑動(dòng)時(shí)不受其他 Mode 影響