一、Runloop的簡單介紹
Runloop 是在程序運(yùn)行過程中循環(huán)做一些事情。比如應(yīng)用在:定時器(NSTimer)、PerformSelector;GCD Async Main Queue;事件響應(yīng)、手勢識別、界面刷新、網(wǎng)絡(luò)請求、AutoreleasePool
- RunLoop的基本作用:保持程序的持續(xù)運(yùn)行;處理App中的各種事件(如觸摸事件、定時器事件等);節(jié)省CPU資源,提高程序性能:該做事時做事,該休息時休息
二、RunLoop對象的獲取
-
2.1、iOS中有2套API來訪問和使用RunLoop
- Foundation:NSRunLoop
- Core Foundation:CFRunLoopRef
-
2.2、NSRunLoop和CFRunLoopRef都代表著RunLoop對象
NSRunLoop是基于CFRunLoopRef的一層OC包裝
CFRunLoopRef是開源的
-
2.3、RunLoop與線程
- 每條線程都有唯一的一個與之對應(yīng)的RunLoop對象
- RunLoop保存在一個全局的Dictionary里,線程作為key,RunLoop作為value
- 線程剛創(chuàng)建時并沒有RunLoop對象,RunLoop會在第一次獲取它時創(chuàng)建
- RunLoop會在線程結(jié)束時銷毀
- 主線程的RunLoop已經(jīng)自動獲?。▌?chuàng)建),子線程默認(rèn)沒有開啟RunLoop
-
2.4、獲取RunLoop對象
-
OC(Foundation)獲取RunLoop對象
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對象 [NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對象 -
C(Core Foundation)獲取RunLoop對象
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對象 CFRunLoopGetMain(); // 獲得主線程的RunLoop對象
-
三、RunLoop相關(guān)的類
Core Foundation中關(guān)于RunLoop的5個類
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
-
3.1、CFRunLoopModeRef
- CFRunLoopModeRef代表RunLoop的運(yùn)行模式
-
一個RunLoop包含若干個Mode,每個Mode又包含若干個Source0/Source1/Timer/Observer
- RunLoop啟動時只能選擇其中一個Mode,作為currentMode
- 如果需要切換Mode,只能退出當(dāng)前Loop,再重新選擇一個Mode進(jìn)入
- 不同組的Source0/Source1/Timer/Observer能分隔開來,互不影響
- 如果Mode里沒有任何Source0/Source1/Timer/Observer,RunLoop會立馬退出
- CFRunLoopModeRef 2種Mode
-
kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認(rèn)Mode,通常主線程是在這個Mode下運(yùn)行 -
UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響
WechatIMG100.jpeg
-
-
3.2、RunLoop的運(yùn)行邏輯
RunLoop的運(yùn)行邏輯- Source0
觸摸事件處理
performSelector:onThread: - Source1
基于Port的線程間通信
系統(tǒng)事件捕捉 - Timers
NSTimer
performSelector:withObject:afterDelay: - Observers
用于監(jiān)聽RunLoop的狀態(tài)
UI刷新(BeforeWaiting)
Autorelease pool(BeforeWaiting)
- Source0

-
3.3、RunLoop休眠的實(shí)現(xiàn)原理
RunLoop休眠的實(shí)現(xiàn)原理
四、RunLoop在實(shí)際開中的應(yīng)用 下面練習(xí)的demo
-
4.1、控制線程生命周期(線程?;睿?/p>
-
(1)OC核心代碼實(shí)現(xiàn)?;?: 看demo里面的類
JKCPermenantThreadself.innerThread = [[MJThread alloc] initWithBlock:^{ // 線程?;? // 往RunLoop里面添加 Source\Timer\Observer [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode]; while (weakSelf && !weakSelf.isStopped) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } }]; -
(2)C核心代碼實(shí)現(xiàn)?;睿嚎磀emo里面的類
ThreadCViewControllerself.innerThread = [[JKThread alloc] initWithBlock:^{ NSLog(@"begin----"); // 創(chuàng)建上下文(要初始化一下結(jié)構(gòu)體) CFRunLoopSourceContext context = {0}; // 創(chuàng)建source CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); // 往Runloop中添加source CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); // 銷毀source CFRelease(source); // 啟動 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, false); // while (weakSelf && !weakSelf.isStopped) { // // 第3個參數(shù):returnAfterSourceHandled,設(shè)置為true,代表執(zhí)行完source后就會退出當(dāng)前l(fā)oop // CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true); // } NSLog(@"end----"); }];
-
-
4.2、解決NSTimer在滑動時停止工作的問題(我在做一個cell上動畫的時候用了NSRunLoop來防止tableview滑動的時候cell上的動畫暫停)
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(clickTimeIndexPath) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; /* UITrackingRunLoopMode和NSDefaultRunLoopMode是真正存在的模式 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; NSRunLoopCommonModes:n并不是一個真的模式,它只是一個標(biāo)記 timer 能在 _commandModes 數(shù)組中存放的模式下工作 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; */ 4.3、監(jiān)控應(yīng)用卡頓(看底層七)
4.4、性能優(yōu)化(看底層七)
五、RunLoop的幾個面試題
5.1、講講 RunLoop,項(xiàng)目中有用到嗎?(你可以回答
四里面的任意一個)
答:我用到了:解決NSTimer在滑動時停止工作的問題(我在做一個cell上動畫的時候用了NSRunLoop來防止tableview滑動的時候cell上的動畫暫停)5.2、runloop內(nèi)部實(shí)現(xiàn)邏輯?
答:看上面的3.2、RunLoop的運(yùn)行邏輯5.3、runloop和線程的關(guān)系?
答:看上面的2.3、RunLoop與線程5.4、timer 與 runloop 的關(guān)系?
答: timer 是運(yùn)行在runloop里面的,runloop控制 timer什么時候執(zhí)行5.5、程序中添加每3秒響應(yīng)一次的NSTimer,當(dāng)拖動tableview時timer可能無法響應(yīng)要怎么解決?
答:看上面的4.2,也就是要添加NSRunLoopCommonModes標(biāo)記5.6、runloop 是怎么響應(yīng)用戶操作的, 具體流程是什么樣的?
答: 由 source1捕獲觸摸或者響應(yīng)事件,再由 source0去處理觸摸或者響應(yīng)事件-
5.7、說說runLoop的幾種狀態(tài)
runLoop的幾種狀態(tài) 5.8、runloop的mode作用是什么?
答:runloop的mode 常用的有兩種mode:NSDefaultRunLoopMode與UITrackingRunLoopMode,在某一種mode下執(zhí)行自己的source0、source1、timer,不同mode下互不影響,分工明確,使用起來更靈活、流暢。





