iOS提供了三種多線程編程的方式:
- 使用NSThread實現多線程;
- 使用NSOperation與NSOperationQueue實現多線程;
- 使用GCD實現多線程實現多線程。
一、使用NSThread實現多線程
iOS系統使用NSThread代表線程,創建新線程也就是創建NSThread對象,創建NSThread的方法有兩種。
(1)-(id) initWithTarget:selector:object: //創建一個新線程對象;
<span style="font-size:14px;">// 創建線程對象
NSThread *thread = [[NSThread alloc]initWithTarget:self
selector:@selector(run) object:nil];
// 啓動新線程
[thread start];</span>
(2)+(void) detachNewThreadSelector:toTarget:withObject: //創建並啓動一個新線程(在OX10.5之前只能通過這種方式來啓動一個線程)
<span style="font-size:14px;">// 創建並啓動新線程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self
withObject:nil];</span>
以上兩種方法的本質都是將target對象的selector方法轉換成線程執行體。
二、使用NSOperation與NSOperationQueue實現多線程
NSOperationQueue:代表一個FIFO隊列,負責管理系統提交的多個NSOperation,NSOperationQueue底層維護一個線程池,會按順序啓動線程來執行提交給該隊列的NSOperation任務。
NSOperation:代表一個多線程任務,有兩個子類:NSInvocationOperation和NSBlockOperation。創建NSOperation對象的方法有兩種,一種是創建自定義類繼承NSOperation,另一種是直接使用NSOperation的兩個子類。
使用NSOperation與NSOperationQueue實現多線程分兩步:
(1)創建NSOperationQueue隊列,併爲該隊列設置屬性;
<span style="font-size:14px;">NSOperationQueue* queue = [[NSOperationQueue alloc]init];
// 設置該隊列最多支持10條併發線程
queue.maxConcurrentOperationCount = 10;</span>
(2)創建NSOperation子類對象,並將該對象提交給NSOperationQueue隊列
<span style="font-size:14px;">// 將NSOperation的子類的實例提交給NSOperationQueue
[queue addOperation:operation];</span>
三、使用GCD實現多線程實現多線程
GCD的基本概念就是dispatch queue。dispatch queue是一個對象,它可以接受任務,並將任務以先到先執行的順序來執行。dispatch queue可以是併發的或串行的,併發任務會像NSOperationQueue那樣基於系統負載來合適地併發進行,串行隊列同一時間只執行單一任務。關於GCD的具體描述請參考Apple官方文檔。
GCD中有三種隊列類型:main queue、global queues和用戶隊列。
(1)main queue:與主線程功能相同,提交至main queue的任務會在主線程中執行,mainqueue可以調用dispatch_get_main_queue() 來獲得。因爲main queue是與主線程相關的,所以這是一個串行隊列。
(2)全局隊列:是併發隊列,並由整個進程共享。進程中存在四個全局隊列:高、中(默認)、低和後臺四個優先級隊列,可以調用dispatch_get_global_queue()函數傳入優先級來訪問指定的全局隊列。
(3)用戶隊列:是用函數 dispatch_queue_create() 創建的隊列,是串行的,可以用來完成同步機制。這裏需要注意的是,使用dispatch_queue_create() 創建的 dispatch queue 對象不受ARC機制的管理(全局隊列和 main queue 不需要手動管理),需要手動進行內存管理,使用 dispatch_release 和 dispatch_retain 函數來操作引用計數。
使用GCD實現多線程也只有兩步:
(1)創建隊列;
(2)將任務提交給隊列。
dispatch_async(提交異步任務)、dispatch_sync(提交同步任務)
向一個隊列提交任務很簡單:調用dispatch_async函數,傳入一個隊列和一個block。隊列會在輪到這個block執行時執行這個block的代碼。
如果希望在任務完成時更新UI界面,也就意味着需要在主線程中執行一些代碼(UI操作必須在主線程中執行)。你可以簡單地完成這個任務——使用嵌套的dispatch,在外層中執行後臺任務,在內層中將任務dispatch到main queue。
<span style="font-size:14px;">dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self goDoSomethingLongAndInvolved];
dispatch_async(dispatch_get_main_queue(), ^{
[textField setStringValue:@"Done doing something long and involved"];
});
});</span>
假設有一段代碼在後臺執行,而它需要從界面控制層獲取一個值,可以使用__block類型修飾符,從執行中的block中獲取一個值。
使用嵌套的block來中止後臺線程,然後從主線程中獲取值,然後再將後期處理提交至後臺線程。
<span style="font-size:14px;">dispatch_queue_t bgQueue = myQueue;
dispatch_async(dispatch_get_main_queue(), ^{
NSString *stringValue = [[[textField stringValue] copy] autorelease];
dispatch_async(bgQueue, ^{
// use stringValue in the background now
...
});
});</span>