1 創建線程
1.1 NSThread
使用 NSThread 來創建線程有兩個可以使用的方法:
1) 使用 detachNewThreadSelector:toTarget:withObject:類方法來生成一個新的線程。
2) 創建一個新的 NSThread 對象,並調用它的 start 方法。
這兩種創建線程的技術都在你的應用程序裡面新建了一個脫離的線程。 一個脫離的線程意味著當線程退出的時候線程的資源由系統自動回收。
1 -(void) myThreadMainMethod如果你擁有一個 NSThread 對象,它的線程當前真正運行,你可以給該線程發送消息的唯一方法是在你應用程序裡面的任何對象使用performSelector:onThread:withObject:waitUntilDone:方法。
1.2 POSIX
Mac OS X 和 iOS 提供基於 C 語言支持的使用 POSIX 線程 API 來創建線程的方法。
1 void* PosixThreadMainRoutine(void* data) //這是C語言的普通函數
1.3 NSObject
在 iOS 和 Mac OS X v10.5 及其之後,所有的對象都可能生成一個新的線程,並用它來執行它任意的方法。方法 performSelectorInBackground:withObject:新生成一個脫離的線程,使用指定的方法作為新線程的主體入口點。
比如,你可以使用當前對象創建一個新的線程:
1 -(void) myThreadMainMethod調用該方法的效果和你在當前對象裡面使用NSThread 的detachNewThreadSelector:toTarget:withObject:傳遞 selectore,object 作為參數的方法一樣。新的線程將會被立即生成並運行,它使用默認的設置。
2 run loop
Run loop 是線程相關的的基礎框架的一部分。一個 run loop 就是一個事件處理的循環,用來不停的調度工作以及處理輸入事件。使用 run loop 的目的是讓你的線程在有工作的時候忙於工作, 而沒工作的時候處於休眠狀態。Run loop相當是Linux系統中的信號處理程序,需要綁定感興趣的信號。
Run loop 的管理並不完全自動的。你仍然需要設計你的線程代碼在合適的時候啟動 run loop 並正確響應輸入事件。 Cocoa 和 Core Fundation 都自動在你應用程序的主線程啟動一個 run loop objects 來幫助配置和管理你線程的 run loop。你的應用程序不需要顯式的創建這些對象(run loop objects);每個線程,包括程序的主線程都有與之對應的 run loop object。 只有輔助線程才需要顯式的運行它的 run loop。
2.1 剖析
Run loop是用來響應產生的事件,在代碼中自己實現循環控制語句,來響應接收到的事件並調用處理程序。Run loop 接收輸入事件來自兩種不同的來源:
如圖 1所示是run loop與source之間的結構,run loop在接收到input source事件後,就會導致runUntilDate方法退出;而接收到timer source事件後,則不會退出。其中run loop除了能接收source事件外,還能產生notifications(消息),並可以指定observers來接收這些消息。
圖 1
2.1.1 模式
run loop 有如下的幾種模式,每種模式都是用來監聽input source、timer source和notifications事件。每次在運行run loop時都需要為run loop指定某種模式:
2.1.2 第一個程序:定時源
如下是一個簡單的定時器功能,其中在0.1秒後將觸發響應方法doFireTimer 。
1 -(void) doFireTimer //定時器觸發方法
2.2 使用
2.2.1 獲得
為了獲得當前線程的 run loop,你可以采用以下任一方式:
1) 使用 NSRunLoop 的 currentRunLoop 類方法來返回一個NSRunLoop 對象;
2) 使用CFRunLoopGetCurrent函數返回一個CFRunLoopRef對象。
如:
1 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; //方式1
CFRunLoopRef 是在 CoreFoundation 框架內的,它提供了純 C 函數的 API,所有這些 API 都是線程安全的。NSRunLoop 是基於 CFRunLoopRef 的封裝,提供了面向對象的 API,但是這些 API 不是線程安全的。NSRunLoop 類定義了一個 getCFRunLoop 方法,該方法返回 一個可以傳遞給 Core Foundation 例程的 CFRunLoopRef 類型。因為兩者都指向同一個run loop。
2.2.2 啟動
run loop有三種啟動方式,不同的啟動方式調用不同的方法,包括以下這些:
表 3
方式
成員函數
描述
無條件
(void)run
最簡單的方法,但也最不推薦使用的,可以添加或刪除輸入源和定時器,但是退出 run loop 的唯一方法是殺死它。沒有任何辦法可以讓這 run loop 運行在自定義模式下。
有限時間
(void)runUntilDate:(NSDate *)limitDate
這種方式一直運行直到到某一事件到達或者規定的時間已經到期。如果是事件到達消息會被傳遞給相應的處理程序來處理,然後run loop 退出。你可以重新啟動 run loop 來等待下一事件。如果是規定時間到期了,你只需簡單的重啟 run loop 或使用此段時間來做任何的其他工作。
特定模式
(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate
這種方式是前兩種方式的結合體。
2.2.3 退出
有兩種方法可以讓 run loop 處理事件之前退出:
1) 給 run loop 設置超時時間
2) 通知 run loop 停止
2.2.4 時機
僅當在為你的程序創建輔助線程的時候,你才需要顯式運行一個 run loop。如果你使用 xcode提供的模板創建的程序,那麼永遠不需要自己顯式的調用這些例程。Run loop 在要和線程有更多的交互時才需要,比如以下情況:
2.3 配置
在你在輔助線程運行 run loop 之前,你必須至少添加一輸入源或定時器給它。 如果 run loop 沒有任何源需要監視的話,它會在你啟動之際立馬退出。
2.3.1 定時源
為了給Run Loop配置一個定時源,只需創建一個定時器(NSTimer)對象並把它添加到NSRunLoop對象中。 其中定時源也有指針類型:CFRunLoopTimerRef,該類型是配合run loop的指針類型CFRunLoopRef使用的。並且將NSTimer 對象添加到NSRunLoop對象中有兩種方式:自動和手動:
1) 自動
這種方式是通過調用NSTimer 的靜態方法scheduledTimerWithTimeInterval,從而自動將創建的NSTimer 對象添加到run loop中。
2) 手動
這種方式是手動創建NSTimer 對象,然後調用NSRunLoop對象的addTimer方法將其添加進入run loop中。
如:
1 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
2.3.2 觀察者
除了安裝源,你也可以添加 run loop 觀察者來監視 run loop 的不同執行階段情況。為了給 run loop 添加一個觀察者,你可以創建 CFRunLoopObserverRef 不透明類型,並使用 CFRunLoopAddObserver 將它添加到你的 run loop。Run loop 觀察者必須由 Core foundation 函數創建,即使是 Cocoa 程序。
1 -(void) myThreadMainMethod
2.3.2 輸入源
對於Apple提供的guide中有關自定義輸入源和port輸入源真心看不懂,為了內容的完整性,所以將此部分添加在此,若有誰清楚這塊內容的,希望能介紹介紹。
3 參考文獻
[1] Threading Programming Guide.