? ? ? ?之前在使用NSTimer時,遇到一個問題,NSTimer啟動了,但是只會出現(xiàn)一次定時,之后就不起作用。問了同事,他說需要加在RunLoop中,我沒有考慮太多,就聽他說的,在外層加了一個Runloop,定時器確實起作用了。近期做另一個任務(wù),發(fā)現(xiàn)RunLoop在多線程中用的比較多,所以大概查了下相關(guān)資料。
? ? ? runLoop是線程中的循環(huán),并對收到的事件進(jìn)行處理,它從兩個不同的事件源中接收消息。Input sources(CFRunLoopSource)投遞異步消息,通常來源于另一個thread或者另一個應(yīng)用程序。Timer sources(CFRunLoopTimer)當(dāng)在計劃的時間或重復(fù)的時間間隔內(nèi)投遞同步消息。兩種事件源都使用應(yīng)用程序指定的處理方式對到達(dá)的事件進(jìn)行處理。下圖展示了run loop和不同的事件源結(jié)構(gòu):

Run Loop的使用場合:
?1. 使用port或是自定義的input source來和其他線程進(jìn)行通信 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2. 在線程(非主線程)中使用timer ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?3. 使用 performSelector…系列(如performSelectorOnThread, …) ? ? ? ? ? ? ? ? ? ? ? ? ?4. 使用線程執(zhí)行周期性工作
run loop不需要創(chuàng)建,在線程中只需要調(diào)用[NSRunLoop currentRunLoop]就可以得到假設(shè)我們想要等待某個異步方法的回調(diào)。比如connection。如果我們的線程中沒有啟動run loop,是不會有效果的(因為線程已經(jīng)運行完畢,正常退出了)。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?使用runLoop阻塞線程的正確寫法 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@implementation ViewController ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BOOL end; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
…
– (void)viewDidLoad ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[super viewDidLoad]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?NSLog(@”start new thread …”); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[NSThread detachNewThreadSelector:@selector(runOnNewThread) ? ? ? ? ? ? ? ? ? ? ? ? ?toTarget:self withObject:nil]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?while (!end) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?NSLog(@”runloop…”); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate: ? ? ? ? [NSDate distantFuture]]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSLog(@”runloop end.”); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSLog(@”ok.”); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
-(void)runOnNewThread ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSLog(@”run for new thread …”); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sleep(1); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self performSelectorOnMainThread:@selector(setEnd) withObject:nil ? ? ? ? ? ? ? ? ? ? ? waitUntilDone:NO]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSLog(@”end.”); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
-(void)setEnd ?{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? end=YES; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
每次運行 Run loop,你線程的 Run loop 對會自動處理之前未處理的消息,并通知相關(guān)的觀察者。具體的順序如下:
1. 通知觀察者 Run loop 已經(jīng)啟動。
2. 通知觀察者任何即將要開始的定時器。
3. 通知觀察者任何即將啟動的非基于端口的源。
4. 啟動任何準(zhǔn)備好的非基于端口的源。
5. 如果基于端口的源準(zhǔn)備好并處于等待狀態(tài),立即啟動;并進(jìn)入步驟 9。
6. 通知觀察者線程進(jìn)入休眠。
7. 將線程置于休眠直到任一下面的事件發(fā)生:
? ?某一事件到達(dá)基于端口的源;
? ?定時器啟動;
? ?Run loop 設(shè)置的時間已經(jīng)超時;
? ?Run loop 被顯式喚醒。
8. 通知觀察者線程將被喚醒。
9. 處理未處理的事件
? ? 如果用戶定義的定時器啟動,處理定時器事件并重啟 Run loop。進(jìn)入步驟 2。
? ? 如果輸入源啟動,傳遞相應(yīng)的消息。
? ? 如果 Run loop 被顯式喚醒而且時間還沒超時,重啟 Run loop,進(jìn)入步驟 2。
10. 通知觀察者 Run loop 結(jié)束。