ios 多線程開關,有關線程的一些用法和詳細講解,NSThread , NSOperation ,Grand Central Dispatch ( GCD )

來源:互聯網
上載者:User

標籤:

IOS支援的多線程技術:

一、Thread:

1)顯式建立線程:NSThreed

2)隱式建立線程:NSObject

二、Cocoa operations:

NSOperation類是一個抽象類別,因為我們必須使用它的兩個子類。

  1)NSInvocationOperation 

2)NSBlockOperation

————————————————————————————

3)NSOperationQueue(繼承於NSObject)

三、Grand Central Dispatch (GCD):

1)GCD的建立

2)重複執行線程:dispatch_apply

3)操作(串列)隊列:dispatch_queue_create

4)GCD群組通知:dispatch_group_t

5)GCD實現計時器

 

以上三種多線程技術的對比:

一、Thread: 

優點:量級較輕。

缺點:需要自己管理線程的生命週期,線程同步。線程同步對資料的加鎖會有一定的系統開銷。

二、Cocoa operations:

優點:不需要關心線程管理,資料同步的事情,可以把精力放在自己需要執行的操作上。

三、Grand Central Dispatch (GCD):

優點:GCD基於C語言的架構,可以充分利用多核,它能夠輕鬆在多核系統上高效運行並發代碼,是蘋果推薦使用的多線程技術。

 

以上三種線程技術,抽象層次從低到高,抽象度越高使用則越簡單,因此蘋果推薦我們使用GCD。

 

Other、線程間通訊:

  在多線程中,所有修改有關於UI介面的東西,必須切換到主線程中修改,不能直接在多線程中修改,不然很容易會出現異常或修改不成功。本文會對三個線程技術說明如何切換至主線程修改UI,具體方法請往下看。

 

一、Thread

我們可以使用NSTherad或NSObject類去調用:

1)顯式建立線程:NSThread

建立NSThread有兩個辦法

1.1)建立之後需要使用start方法,才會執行方法:

NSThread *threadAlloc = [[NSThread alloc] initWithTarget:self selector:@selector(threadAlloc) object:nil];[threadAlloc start];

 

1.2)建立並馬上執行方法:

[NSThread detachNewThreadSelector:@selector(threadAlloc:) toTarget:self withObject:nil];

 

2)隱式建立線程:NSObject

我們也可以使用NSObject類的方法直接調用方法

[self performSelectorInBackground:@selector(threadAlloc) withObject:nil];

 

取消線程的方法:

實際上並沒有真正提供取消線程的API。蘋果提供了一個cancel的api,但它不能作用於取消線程,它只能改變線程的運行狀態。我們可以使用它來進行條件判斷。

- (void)threadCancel{    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadCancelNow) object:nil];    [thread start];}- (void)threadCancelNow{    int a = 0;    while (![[NSThread currentThread] isCancelled]) {        NSLog(@"a - %d", a);        a++;        if (a == 5000) {            NSLog(@"終止迴圈");            [[NSThread currentThread] cancel];            break;        }    }}

程式效果:迴圈輸出5000次,線程就會被終止。

 

NSThread線程間通訊-調用主線程修改UI:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; 

 

NSThread相關屬性及方法:

// 擷取/設定線程的名字@property (copy) NSString *name NS_AVAILABLE(10_5, 2_0);/** *  擷取當前線程的線程對象 * *  通過這個屬性可以查看當前線程是第幾條線程,主線程為1。 *  可以看到當前線程的序號及名字,主線程的序號為1,依次疊加。 */+ (NSThread *)currentThread;// 線程休眠(秒)+ (void)sleepForTimeInterval:(NSTimeInterval)ti;// 線程休眠,指定具體什麼時間休眠+ (void)sleepUntilDate:(NSDate *)date;// 退出線程 // 注意:這裡會把線程對象銷毀!銷毀後就不能再次啟動線程,否則程式會崩潰。+ (void)exit;

 

 

二、Cocoa operations

1)NSInvocationOperation

// 建立線程任務NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 線程ANSInvocationOperation *operation = [[NSInvocationOperation alloc]                                    initWithTarget:self                                    selector:@selector(operation1)                                    object:nil];// 線程BNSInvocationOperation *operation2 = [[NSInvocationOperation alloc]                                    initWithTarget:self                                    selector:@selector(operation2)                                    object:nil];// 把線程A/B添加至隊列[queue addOperations:@[operation, operation2] waitUntilFinished:YES];

必須使用addOperations:方法把線程添加至隊列,不然線程不會執行,隊列是並存執行。或者,你也可以使用addOperation:方法添加單個線程。

 

2)NSBlockOperation

舉個簡單的使用例子介紹,都寫了備忘,就不再說明了:

// 建立線程任務NSBlockOperation *blockOperation = [NSBlockOperation                                    blockOperationWithBlock:^{                                        [NSThread sleepForTimeInterval:2];                                        NSLog(@"one - %@", [NSThread currentThread]);                                    }];;// 添加新的操作[blockOperation addExecutionBlock:^{    NSLog(@"two - %@", [NSThread currentThread]);}];// 添加新的操作[blockOperation addExecutionBlock:^{    NSLog(@"three - %@", [NSThread currentThread]);}];// 執行線程任務[blockOperation start];

例子效果:使用類方法blockOperationWithBlock:建立的塊代碼,是在主線程當中執行的,我們可以從列印出來的資訊看到。其它使用addExecutionBlock:添加的子線程為並發線程。

 

3)NSOperationQueue

這裡介紹一下NSOperation的依賴關係,依賴關係會影響線程的執行順序:

// 建立操作隊列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 線程ANSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{    NSLog(@"op1");    [NSThread sleepForTimeInterval:2];}];// 線程BNSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{    NSLog(@"op2");}];// 線程CNSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{    NSLog(@"op3");    [NSThread sleepForTimeInterval:2];}];// 線程B依賴線程C,也就是等線程C執行完之後才會執行線程B[op2 addDependency:op3];// 線程C依賴線程A,同上,只不過依賴對象改成了線程A[op3 addDependency:op1];// 為隊列添加線程[queue addOperation:op1];[queue addOperation:op2];[queue addOperation:op3];

當你沒添加依賴時,隊列是並存執行的。

注意:依賴關係可以多重依賴,但不要建立循環相依性。

 

Cocoa operations線程間通訊-調用主線程修改UI:

// 建立線程對象(並發)NSBlockOperation *blockOperation = [[NSBlockOperation alloc] init];// 添加新的操作[blockOperation addExecutionBlock:^{    NSLog(@"two - %@", [NSThread currentThread]);}];// 添加新的操作[blockOperation addExecutionBlock:^{    NSLog(@"three - %@", [NSThread currentThread]);    // 在主線程修改UI    NSOperationQueue *queue = [NSOperationQueue mainQueue];    [queue addOperationWithBlock:^{        [self editUINow];    }];}];[blockOperation start];

 

 NSOperation方法及屬性:

// 設定線程的最大並發數@property NSInteger maxConcurrentOperationCount;// 線程完成後調用的Block@property (copy) void (^completionBlock)(void);// 取消線程- (void)cancel;

只列舉上面那些,其它的方法就不全列出來了。

 

注意:在NSOperationQueue類中,我們可以使用cancelAllOperations方法取消所有的線程。這裡需要說明一下,不是執行cancelAllOperations方法時就會馬上取消,是等當前隊列執行完,下面的隊列不會再執行。

 

三、Grand Central Dispatch (GCD)

1)GCD的建立:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    NSLog(@"線程 - %@", [NSThread currentThread]);});

GCD也可以建立同步的線程,只需要把async改成sync即可。

 

2)重複執行線程:dispatch_apply

以下代碼會執行4次:

dispatch_apply(4, DISPATCH_QUEUE_PRIORITY_DEFAULT, ^(size_t index) {    // index則為執行的次數 0開始遞增    NSLog(@"one - %ld", index);});

index參數為執行的次數,從0開始遞增

 

3)操作隊列:dispatch_queue_create

// 建立隊列// 第一個參數是“字串標識”,第二個參數是可選的,可以是NULLdispatch_queue_t queue = dispatch_queue_create("com.garvey.post", NULL);// 傳入一個隊列並執行隊列(順序執行)dispatch_async(queue, ^{    NSLog(@"aaa");    [NSThread sleepForTimeInterval:2];});dispatch_async(queue, ^{    NSLog(@"bbb");    [NSThread sleepForTimeInterval:1];});dispatch_async(queue, ^{    NSLog(@"ccc");});

代碼效果:以上會先執行aaa-》bbb-》ccc,是一個串列隊列。

 

4)GCD群組通知:dispatch_group_t

GCD的進階用法,等所有線程都完成工作後,再作通知。

// 建立群組dispatch_group_t group = dispatch_group_create();// 線程Adispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    NSLog(@"group1");    [NSThread sleepForTimeInterval:2];});// 線程Bdispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    NSLog(@"group2");});// 待群組裡的線程都完成之後調用的通知dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    NSLog(@"group success");});

群組裡的線程也是並行隊列。線程A和線程B都執行完之後,會調用通知列印group success。

 

5)GCD實現計時器

__block int time = 30;dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0);dispatch_source_set_event_handler(timer, ^{    time--;    NSLog(@"%d", time);    if (time == 0) {        dispatch_source_cancel(timer);    }});dispatch_resume(timer);

代碼效果:建立了一個計時器,計時器運行30秒,每過一秒會調用一次block,我們可以在block裡面寫代碼。因為dispatch_source_t預設是掛起狀態,因此我們使用時需要使用dispatch_resume方法先恢複,不然線程不會執行。

 

GCD線程間通訊-調用主線程修改UI:

有時候我們請求後台作資料處理,資料處理是非同步,資料處理完成後需要更新UI,這時候我們需要切換到主線程修改UI,例子如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    NSLog(@"非同步資料處理 - %@", [NSThread currentThread]);    [NSThread sleepForTimeInterval:2];    NSLog(@"資料處理完成");        // 調用主線程更新UI    dispatch_sync(dispatch_get_main_queue(), ^{        NSLog(@"更新UI - %@", [NSThread currentThread]);        [self editUINow];    });});

因為是在主線程修改UI,所以我們最好是使用同步的GCD方法dispatch_sync。但這還不夠,我們還需要使用dispatch_get_main_queue()方法來獲得主線程,之後就是作UI的更新工作了。

 

GCD方法及屬性:

// 擷取主線程dispatch_get_main_queue()// 建立隊列:第一個參數是“字串標識”,第二個參數是可選的,可以是NULLdispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);// 建立非同步調度隊列void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);// 恢複隊列void dispatch_resume(dispatch_object_t object);// 暫停隊列void dispatch_suspend(dispatch_object_t object);

 

轉自GarveyCalvin

原文連結:http://www.cnblogs.com/GarveyCalvin/

 

ios 多線程開關,有關線程的一些用法和詳細講解,NSThread , NSOperation ,Grand Central Dispatch ( GCD )

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.