iOS 多線程

因為什么,我最新重新學習了多線程的知識,順便總結(jié)一下。

首先,為什么要使用多線程,在iOS中我們希望主線程可以快速地響應用戶操作,不能停止對用戶操作的監(jiān)聽,這就需要其他線程來替主線程執(zhí)行一些非響應用戶操作并且可能耗時的任務。否則,如果讓主線程來執(zhí)行耗時的操作,比如從網(wǎng)絡上獲取數(shù)據(jù),只有這個獲取數(shù)據(jù)的任務結(jié)束,主線程才可以繼續(xù)響應用戶操作,這段時間主線程就被阻塞了,這就是我們不愿意看到的。

一次面試被問道線程和進程的區(qū)別,筆畫的半天也沒有說清楚。 蘋果官方解釋:

The term thread is usedtorefertoaseparate pathofexecutionforcode.

線程用于指代一個獨立執(zhí)行的代碼路徑。

The termprocessis usedtorefertoarunning executable, which can encompass multiple threads.

進程用于指代一個可執(zhí)行程序,他可以包含多個線程。

線程和進程的區(qū)別:??? 發(fā)現(xiàn)還是不能用自己的話表達出來,哦哦。繼續(xù)學習。

iOS多線程有三種技術:NSThread NSOperation ?GCD

GCD(Grand Central Dispatch)

GCD現(xiàn)在在項目中使用的較多,我們可以不用考慮線程安全,不用考慮線程相關的操作,你只需要想清楚任務的執(zhí)行方法(同步還是異步)和隊列的運行方式(串行還是并行)就可以,但是GCD不提供cancel方法,如果你的需求需要cancel就必須考慮其他的方案。

dispatch_queue dispatch_group_t

GCD提供至少5種隊列:全局隊列4個 主隊列 自定義隊列(可以創(chuàng)建串行隊列 和并行隊列)

GCD 提供有dispatch queues來處理代碼塊,這些隊列管理你提供給 GCD 的任務并用 FIFO 順序執(zhí)行這些任務。 所有的調(diào)度隊列(dispatch queues)自身都是線程安全的,你能從多個線程并行的訪問它們。 ?

GCD提供 創(chuàng)建一個隊列

dispatch_queue_t my_queue = dispatch_queue_create("com.open.js",NULL);

自定義隊列的第一個參數(shù)用于表示一個隊列,DISPATCH_QUEUE_SERIAL或者NULL表示創(chuàng)建一個串行隊列,DISPATCH_QUEUE_CONCURRENT表示創(chuàng)建一個并行隊列.

以下用一段代碼說明:GCD中的異步,全局隊列,主隊列,group等相關用法。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 1.

__block NSError *error;

dispatch_group_t downloadGroup = dispatch_group_create(); // 2.

dispatch_group_enter(downloadGroup); // 3.

Photo *photo = [[Photo alloc] initwithURL:url

withCompletionBlock:^(UIImage *image, NSError *_error) {

if (_error) {

error = _error;}

dispatch_group_leave(downloadGroup);

}];

[[PhotoManager sharedManager] addPhoto:photo];

}

// a.

dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); // 4.

dispatch_async(dispatch_get_main_queue(), ^{ // 5.

if (completionBlock) {

completionBlock(error);

}

});

dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{ //5.

if (completionBlock) {

completionBlock(error);

}

});

以上代碼開始創(chuàng)建一個group,等group內(nèi)任務全部完成后回調(diào)主線程使用GCD的寫法.

1.由于dispatch_group_wait會一個阻塞線程,所以要加入一個異步線程,

2.創(chuàng)建一個dispatch_group_t

3.手動通知dipatch_group已經(jīng)開始,必須保證dispatch_group_enter和dispatch_group_level配對使用

4. dispatch_group_wait一直等待直到成功,參數(shù)可以設置等待時間,目前是永遠等待

5.成功之后回調(diào)主線程,繼續(xù)執(zhí)行相關工作

6. 其中a.一直等待直到成功后異步回調(diào)主線程。b.group內(nèi)任務完成后通過dispatch_group_notify回調(diào)主線程。多使用b方法.

GCD中有2個異步的API

void dispatch_async(dispatch_queue_tqueue, dispatch_block_t block);

void dispatch_async_f(dispatch_queue_tqueue,void*context, dispatch_function_t work);

他們都是將一個任務提交到queue中,提交之后立即返回,不等待任務的的執(zhí)行。提交之后,系統(tǒng)會對queue做retain操作,任務執(zhí)行完成之后,queue再被release。兩個函數(shù)實際的功能是一樣的,唯一的區(qū)別在于dispatch_async接受block作為參數(shù),dispatch_async_f接受函數(shù)。

使用dispatch_async的時候block會被copy,在block執(zhí)行完成之后block再release,由于是系統(tǒng)持有block,所以不用擔心循環(huán)引用的問題,block里面的self不需要weak

在dispatch_async_f中,context會作為第一個參數(shù)傳給work函數(shù)。如果work不需要參數(shù),context可以傳入NULL。work參數(shù)不能傳入NULL,否則可能發(fā)生無法預料的事兒

同樣GCD提供2個同步api,調(diào)用方法只是把async換為sync即可。

另外比較常用的幾個 ?dispatch_once ?dispatch_after ?dispatch_barriers(可以用來解決讀寫鎖問題)

NSOperation & NSOperationQueue

NSOperation可以通過調(diào)用start方法同步地執(zhí)行相應的任務,不過通常NSOprtaion都是配合NSOPerationQueue來使用的,NSOperationQueue可以看作是一種高級的dispatch queue,將NSOperation加入到queue中,queue會自動異步的執(zhí)行該NSOperation.

我們通常情況下使用GCD較多,但是我們沒法取消block內(nèi)的任務,這時候就需要使用NSOperation實現(xiàn)異步。NSOperation可以提供cancel,設置最大并發(fā)數(shù),任務的暫停繼續(xù),設置隊列優(yōu)先級,設置任務的依賴關系等。

如果并發(fā)的任務是異步任務時,你需要的是繼承NSOperation并至少實現(xiàn)start、isExecuting和isFinished方法,其中isExecuting跟isFinished兩個屬性值的改變需要做KVO通知。

[operation cancel]; // 取消一個任務

[queuecancelAllOperations];// 取消queue中所有的任務

queue.maxConcurrentOperationCount =2;//設置并發(fā)數(shù)目為2

[queue setSuspended:YES];// 暫停隊列運行任務

[queue setSuspended:NO];// 繼續(xù)


NSThread

對于NSThread來說,每個對象就代表著一個線程。NSThread提供兩種創(chuàng)建方法:

+ (void)detachNewThreadSelector:(SEL)selectortoTarget:(id)targetwithObject:(nullableid)argument;

-(instancetype)initWithTarget:(id)targetselector:(SEL)selectorobject:(nullableid)argumentNS_AVAILABLE(10_5, 2_0);

detach方法直接創(chuàng)建并啟動一個線程去Selector,由于沒有返回值,如果需要獲取新創(chuàng)建的Thread,需要在執(zhí)行的Selector中調(diào)用[NSThread currentThread]獲取

init方法初始化線程并返回,線程的入口函數(shù)由Selector傳入。線程創(chuàng)建出來之后需要手動調(diào)用-start方法啟動.

創(chuàng)建好線程只后可以對線程進行操作,NSThread給線程提供的主要操作方法有:啟動,睡眠,取消和退出。

線程操作

我們使用init方法初始化的方法并不會啟動線程,需要我們手動調(diào)-start方法啟動線程:

-(void)start NS_AVAILABLE(10_5,2_0);

NSThread提供了2個讓線程睡眠的方法,一個是根據(jù)NSDate傳入睡眠時間,一個是直接傳入NSTimeInterval

+ (void)sleepUntilDate:(NSDate*)date;

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

對于線程的取消,NSThread提供了一個取消的方法和一個屬性

@property(readonly, getter=isCancelled)BOOL cancelled;

- (void)cancel NS_AVAILABLE(10_5,2_0);

不過調(diào)用-cancel方法并不會立刻取消線程,它僅僅是將cancelled屬性設置為YES。cancelled也僅僅是一個用于記錄狀態(tài)的屬性。線程取消的功能需要我們在main函數(shù)中自己實現(xiàn)。要實現(xiàn)取消的功能,我們需要自己在線程的main函數(shù)中定期檢查isCancelled狀態(tài)來判斷線程是否需要退出,當isCancelled為YES的時候,我們手動退出。如果沒有在main函數(shù)中檢查isCancelled狀態(tài),那么調(diào)用-cancel將沒有任何意義。

與充滿不確定性的-cancel相比,-exit函數(shù)可以讓線程立即退出。但是exit方法會立即終止線程,即使線程中有沒有終止的任務,所以要慎用。

+ (void)exit;

線程交互
線程準備好之后,經(jīng)常需要從主線程把耗時的任務丟給輔助線程,當任務完成之后輔助線程再把結(jié)果傳回主線程傳,這些線程通訊一般用的都是perform方法。望文生義就可以知道這些方法的用途了。

//①-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullableNSArray *)array;

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

//③-(void)performSelector:(SEL)aSelector onThread:(NSThread*)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullableNSArray *)array NS_AVAILABLE(10_5,2_0);

//④-(void)performSelector:(SEL)aSelector onThread:(NSThread*)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5,2_0);

三者的優(yōu)缺點

三者的使用場景

使用一個項目說明以上相關內(nèi)容,實踐出真理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 一、前言 上一篇文章iOS多線程淺匯-原理篇中整理了一些有關多線程的基本概念。本篇博文介紹的是iOS中常用的幾個多...
    nuclear閱讀 2,146評論 6 18
  • 在這篇文章中,我將為你整理一下 iOS 開發(fā)中幾種多線程方案,以及其使用方法和注意事項。當然也會給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 698評論 0 0
  • 歡迎大家指出文章中需要改正或者需要補充的地方,我會及時更新,非常感謝。 一. 多線程基礎 1. 進程 進程是指在系...
    xx_cc閱讀 7,383評論 11 70
  • 在這篇文章中,我將為你整理一下 iOS 開發(fā)中幾種多線程方案,以及其使用方法和注意事項。當然也會給出幾種多線程的案...
    伯恩的遺產(chǎn)閱讀 275,634評論 251 2,328
  • 陌陌無圖考慮考慮可口可樂了看看
    吉爾伽美什_閱讀 233評論 0 0

友情鏈接更多精彩內(nèi)容