1. 程式人生 > >Run loop和Thread

Run loop和Thread

Run-loop是什麼?

首先考慮這個問題:你的Cocoa程式大部分的時間什麼都沒做,更具體點,是在等待輸入。然而,一旦你觸控式螢幕幕,相應的事件被觸發,就可能會執行你的一段事件處理程式碼。同理,socket中返回一些資料,或者計時器觸發等也是一樣的情況。而且更重要的是,一旦觸發事件的程式碼執行完,程式就會回到等待狀態。在很多情況下,程式碼執行的時間要遠小於程式等待輸入的時間。

我認為run loop就是較好的利用了這個事實的一種機制。一個run loop就是跑在單個執行緒上進行事件處理的迴圈。你在run loop上註冊輸入源,並指定當這些源有輸入時應該執行的程式碼。當特定的源上有輸入時,run loop就會執行對應的程式碼,然後繼續等待下一個輸入事件。如果在run loop正在執行處理程式碼時,另外一個源的輸入到了,run loop會在執行完正當前的處理後處理這個輸入事件。好處是雖然你不知道具體的輸入順序,但你知道它們最終會一個接一個地被序列處理。這就是說你不會遇到多執行緒的問題,這也是run loop非常有用的原因。

和執行緒的關係?

每個執行緒,包括應用的主執行緒都有一個相關聯的run loop物件,在應用中你不需要顯式的建立run loop物件。在Carbon和Cocoa應用中,主執行緒會自動設定並執行它的run loop,這個過程也是應用啟動過程的一部分。

Run loop的使用

預設情況下,iPhone上的所有觸控事件都會被main run loop放在佇列裡等待處理,所以你不需要對UI元件做額外的事情,而其他輸入源需要一些額外的編碼。比如在run loop上schedule一個NSInputStream,你需要像下面這樣:

[iStream setDelegate:self];
[iStream
scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

在上面的程式碼中,一旦iStream有輸入資料,就會執行selfstream:handleEvent的方法。而且這個stream可以是任意型別的輸入源,包括socket.

另外,timer物件也可以被schedule在run loop上,比如:

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(doStuff) userInfo: nil
repeats:YES];

上面的程式碼把計時器schedule到當前的run loop上,每2秒就會呼叫selfdoStuff方法。

不適用run loop的情況

那什麼時候不適合使用run loop呢?根據run loop的特點,輸入事件會一個接一個的被序列處理,那麼如果一個事件的處理需要的時間特別長的話,就會導致在這個事件處理完之前,app無法響應別的輸入事件。在這種情況下,新開一個執行緒處理更合適。 然而,大部分情況下,我們的程式碼處理螢幕、socket或者計時器事件都非常快,這時使用main run loop處理起來更簡單,也更安全。