iOS 多線程

原文: 查看原文 , 原作者寫的非常詳細, 本文摘取了個人認為比較有用且易理解的部分, 碼一遍增強理解, 大家可以移步原文閱讀.

iOS 中可用的4套多線程方案, 并不都建議使用, 視情況而定
  • Pthreads
  • NSThread
  • GCD
  • NSOperation & NSOperationQueue

Pthreads

可移植性很強, 但由于基于 c語言框架, 所以并不建議使用.

#import <pthread.h>

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    pthread_t thread;
    //創(chuàng)建一個線程并自動執(zhí)行
    pthread_create(&thread, NULL, start, NULL);
}

void *start(void *data) {
    NSLog(@"%@", [NSThread currentThread]);

    return NULL;
}

需要手動管理生命周期


NSThread

經(jīng)過蘋果封裝, 可以直接操控線程對象. 通過[NSThread currentThread]獲取當前線程類及各種屬性.

  • 先創(chuàng)建線程類 再啟動
  // 創(chuàng)建
  NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];

  // 啟動
  [thread start];
  • 創(chuàng)建并自動啟動
  [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
  • 使用 NSObject 方法創(chuàng)建并自動啟動
  [self performSelectorInBackground:@selector(run:) withObject:nil];
  • 判斷某個線程狀態(tài)的屬性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
  • 設(shè)置和獲取線程名字
-(void)setName:(NSString *)n;
-(NSString *)name;
  • 獲取線程信息
//獲取當前線程信息
+ (NSThread *)currentThread;

//獲取主線程信息
+ (NSThread *)mainThread;
  • 當前線程暫停
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;

不夠優(yōu)雅


GCD - 大調(diào)度中心!

自動管理生命周期 , 雖然使用 c語言 但是由于使用了 Block, 所以用起來非常方便.

使用 GCD 只有兩個步驟:
1. 定制任務(wù)
2. 確定想做的事

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block) 將右邊的任務(wù)提交給左邊的隊列執(zhí)行.

同步( sync )異步( async )最大的區(qū)別在于會不會阻塞當前線程, 直到 Block 中的任務(wù)執(zhí)行完畢.

同步( sync ) 它會阻塞當前線程并等待 Block 中的任務(wù)執(zhí)行完畢蹦疑,然后當前線程才會繼續(xù)往下運行。
異步( async ) 當前線程會直接往下執(zhí)行萨驶,它不會阻塞當前線程歉摧。

串行隊列 放到串行隊列的任務(wù),GCD 會 FIFO(先進先出) 地取出來一個,執(zhí)行一個叁温,然后取下一個再悼,這樣一個一個的執(zhí)行。
并行隊列 放到并行隊列的任務(wù)膝但,GCD 也會 FIFO的取出來冲九,但不同的是,它取出來一個就會放到別的線程跟束,然后再取出來一個又放到另一個的線程莺奸。這樣由于取的動作很快,忽略不計冀宴,看起來灭贷,所有的任務(wù)都是一起執(zhí)行的。不過需要注意花鹅,GCD 會根據(jù)系統(tǒng)資源控制并行的數(shù)量氧腰,所以如果任務(wù)很多,它并不會讓所有任務(wù)同時執(zhí)行刨肃。

注: 無論是串行隊列還是并行隊列 , 都遵守先進先出 FIFO 原則 , 只是并行隊列允許同時執(zhí)行多個任務(wù).

|同步執(zhí)行 | 異步執(zhí)行
---|--------|-------
串行隊列 | 當前線程古拴,一個一個執(zhí)行 | 其他線程,一個一個執(zhí)行
并行隊列 | 當前線程真友,一個一個執(zhí)行 | 開很多線程黄痪,一起執(zhí)行

創(chuàng)建隊列

  • 主隊列 : 用于刷新 UI,任何需要刷新 UI 的工作都要在主隊列執(zhí)行盔然,所以一般耗時的任務(wù)都要放到別的線程執(zhí)行桅打。
  dispatch_queue_t queue = ispatch_get_main_queue();
  • 自己創(chuàng)建隊列 : 自己可以創(chuàng)建 串行隊列, 也可以創(chuàng)建 并行隊列
    • 第一個參數(shù)是標識符愈案,用于 DEBUG 的時候標識唯一的隊列挺尾,可以為空烦周。
    • 第二個參數(shù)用來表示創(chuàng)建的隊列是串行的還是并行的冈敛,傳入 DISPATCH_QUEUE_SERIAL 或 NULL 表示創(chuàng)建串行隊列。傳入 DISPATCH_QUEUE_CONCURRENT 表示創(chuàng)建并行隊列振乏。
  //串行隊列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
  //并行隊列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
  • 全局并行隊列 : 只要是并行任務(wù)一般都加入到這個隊列恢准。這是系統(tǒng)提供的一個并發(fā)隊列魂挂。
  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

創(chuàng)建任務(wù)

  • 同步任務(wù)( sync ): 會阻塞當前線程
  dispatch_sync(<#queue#>, ^{
      //code here
      NSLog(@"%@", [NSThread currentThread]);
  });
  • 異步任務(wù)( async ): 不會阻塞
dispatch_async(<#queue#>, ^{
      //code here
      NSLog(@"%@", [NSThread currentThread]);
  });

NSOperation和NSOperationQueue

NSOperation 是蘋果公司對 GCD 的封裝,完全面向?qū)ο竽倏穑允褂闷饋砀美斫狻?大家可以看到 NSOperationNSOperationQueue 分別對應 GCD 的 任務(wù)隊列 涂召。

添加任務(wù)

NSOperation 只是一個抽象類,所以不能封裝任務(wù)敏沉。但它有 2 個子類用于封裝任務(wù)果正。分別是:NSInvocationOperationNSBlockOperation 炎码。創(chuàng)建一個 Operation 后,需要調(diào)用 start 方法來啟動任務(wù)舱卡,它會 默認在當前隊列同步執(zhí)行辅肾。當然你也可以在中途取消一個任務(wù)队萤,只需要調(diào)用其 cancel 方法即可轮锥。

  • NSInvocationOperation : 傳入一個方法
//1.創(chuàng)建NSInvocationOperation對象
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

  //2.開始執(zhí)行
  [operation start];
  • NSBlockOperation
  //1.創(chuàng)建NSBlockOperation對象
  NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"%@", [NSThread currentThread]);
  }];

  //2.開始任務(wù)
  [operation start];

默認會在當前線程執(zhí)行。但是 NSBlockOperation 還有一個方法:addExecutionBlock: 要尔,通過這個方法可以給 Operation 添加多個執(zhí)行 Block舍杜。這樣 Operation 中的任務(wù) 會并發(fā)執(zhí)行,它會在主線程和其它的多個線程 執(zhí)行這些任務(wù)

 //1.創(chuàng)建NSBlockOperation對象
      NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
          NSLog(@"%@", [NSThread currentThread]);
      }];

      //添加多個Block
      for (NSInteger i = 0; i < 5; i++) {
          [operation addExecutionBlock:^{
              NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
          }];
      }

      //2.開始任務(wù)
      [operation start];

NSOperationQueue 有一個參數(shù) maxConcurrentOperationCount 最大并發(fā)數(shù)赵辕,用來設(shè)置最多可以讓多少個任務(wù)同時執(zhí)行既绩。當你把它設(shè)置為 1 的時候,就是串行.

NSOperationQueue 還有一個添加任務(wù)的方法还惠,- (void)addOperationWithBlock:(void (^)(void))block; 饲握,這是不是和 GCD 差不多?這樣就可以添加一個任務(wù)到隊列中了蚕键,十分方便救欧。

//1.任務(wù)一:下載圖片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"下載圖片 - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:1.0];
}];

//2.任務(wù)二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"打水印   - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:1.0];
}];

//3.任務(wù)三:上傳圖片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"上傳圖片 - %@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:1.0];
}];

//4.設(shè)置依賴
[operation2 addDependency:operation1];      //任務(wù)二依賴任務(wù)一
[operation3 addDependency:operation2];      //任務(wù)三依賴任務(wù)二

//5.創(chuàng)建隊列并加入任務(wù)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
  • 注意:不能添加相互依賴,會死鎖锣光,比如 A依賴B笆怠,B依賴A。
  • 可以使用 removeDependency 來解除依賴關(guān)系誊爹。
  • 可以在不同的隊列之間依賴蹬刷,反正就是這個依賴是添加到任務(wù)身上的,和隊列沒關(guān)系频丘。

延遲執(zhí)行

  • perform
// 3秒后自動調(diào)用self的run:方法办成,并且傳遞參數(shù):@"abc"
  [self performSelector:@selector(run:) withObject:@"abc" afterDelay:3];
  • GCD
// 創(chuàng)建隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 設(shè)置延時,單位秒
double delay = 3; 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
    // 3秒后需要執(zhí)行的任務(wù)
});
  • NSTimer
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(run:) userInfo:@"abc" repeats:NO];

從其他線程回到主線程

  • NSThread
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
  • GCD
dispatch_async(dispatch_get_main_queue(), ^{

});
  • NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{

}];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搂漠,一起剝皮案震驚了整個濱河市迂卢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌状答,老刑警劉巖冷守,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惊科,居然都是意外死亡拍摇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門馆截,熙熙樓的掌柜王于貴愁眉苦臉地迎上來充活,“玉大人蜂莉,你說我怎么就攤上這事』炻眩” “怎么了映穗?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幕随。 經(jīng)常有香客問我蚁滋,道長,這世上最難降的妖魔是什么赘淮? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任辕录,我火速辦了婚禮,結(jié)果婚禮上梢卸,老公的妹妹穿的比我還像新娘走诞。我一直安慰自己,他們只是感情好蛤高,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布蚣旱。 她就那樣靜靜地躺著,像睡著了一般戴陡。 火紅的嫁衣襯著肌膚如雪塞绿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天猜欺,我揣著相機與錄音位隶,去河邊找鬼。 笑死开皿,一個胖子當著我的面吹牛涧黄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赋荆,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼笋妥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窄潭?” 一聲冷哼從身側(cè)響起春宣,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嫉你,沒想到半個月后月帝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡幽污,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年嚷辅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片距误。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡簸搞,死狀恐怖扁位,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情趁俊,我是刑警寧澤域仇,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站寺擂,受9級特大地震影響暇务,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽讹,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一般卑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爽雄,春花似錦、人聲如沸沐鼠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饲梭。三九已至乘盖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間憔涉,已是汗流浹背订框。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兜叨,地道東北人穿扳。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像国旷,于是被迫代替她去往敵國和親矛物。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 多線程 在iOS開發(fā)中為提高程序的運行效率會將比較耗時的操作放在子線程中執(zhí)行跪但,iOS系統(tǒng)進程默認啟動一個主線程履羞,用...
    郭豪豪閱讀 2,601評論 0 4
  • 在這篇文章中,我將為你整理一下 iOS 開發(fā)中幾種多線程方案屡久,以及其使用方法和注意事項忆首。當然也會給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 603評論 0 0
  • 學習多線程,轉(zhuǎn)載兩篇大神的帖子被环,留著以后回顧糙及!第一篇:關(guān)于iOS多線程,你看我就夠了 第二篇:GCD使用經(jīng)驗與技巧...
    John_LS閱讀 621評論 0 3
  • 多線程基本概念 單核CPU蛤售,同一時間cpu只能處理1個線程,只有1個線程在執(zhí)行 丁鹉。多線程同時執(zhí)行:是CPU快速的在...
    WeiHing閱讀 709評論 1 5
  • 在這篇文章中揣钦,我將為你整理一下 iOS 開發(fā)中幾種多線程方案雳灾,以及其使用方法和注意事項。當然也會給出幾種多線程的案...
    伯恩的遺產(chǎn)閱讀 274,579評論 251 2,331