iOS中的多執行緒(關於NSOperationQueue)
highlight: a11y-dark theme: cyanosis
「這是我參與11月更文挑戰的第12天,活動詳情檢視:2021最後一次更文挑戰」
關於NSOperationQueue
NSOperationQueue
一共有兩種佇列:
- 主佇列
```js
//獲取主佇列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
```
- 自定義佇列:通過設定最大併發數屬性來控制任務是併發執行還是序列執行
- 併發執行
- 序列執行
js //獲取自定義佇列 NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSInvocationOperation 和 NSOperationQueue 組合
示例: ```js //建立佇列(建立的佇列中的任務預設是非同步執行的) NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//建立任務 NSInvocationOperation op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run1) object:nil]; NSInvocationOperation op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run2) object:nil];
//任務新增佇列 [queue addOperation:op1]; [queue addOperation:op2];
- (void)run1{ NSLog(@"1-- %@",[NSThread currentThread]); }
- (void)run2{ NSLog(@"2-- %@",[NSThread currentThread]); } ``` log:
NSInvocationOperation 和 NSBlockOperation 組合
示例: ```js //建立佇列(建立的佇列中的任務預設是非同步執行的) NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//建立任務 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1-- %@",[NSThread currentThread]); }];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2-- %@",[NSThread currentThread]); }];
//新增額外任務 [op1 addExecutionBlock:^{ NSLog(@"3-- %@",[NSThread currentThread]); }];
//新增額外任務 [op1 addExecutionBlock:^{ NSLog(@"4-- %@",[NSThread currentThread]); }];
//任務新增佇列 [queue addOperation:op1]; [queue addOperation:op2];
//可以直接建立任務到佇列中去 [queue addOperationWithBlock:^{ NSLog(@"5-- %@",[NSThread currentThread]); }]; ``` log:(任務都是併發執行的)
NSInvocationOperation 和 自定義NSOperation 組合
示例: ```js //建立佇列(建立的佇列中的任務預設是非同步執行的) NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//建立任務需要繼承NSOperation,執行的操作需要放在這個自定義類的main中 Operation *op1 = [[Operation alloc]init];
//建立任務需要繼承NSOperation,執行的操作需要放在這個自定義類的main中 Operation *op2 = [[Operation alloc]init];
//任務新增佇列 [queue addOperation:op1]; [queue addOperation:op2]; ``` log:
NSOperation其它用法
設定最大併發數(控制任務併發和序列)
- 最大併發數:佇列在同一時間中最多有多少個任務可以執行
- 通過屬性
maxConcurrentOperationCount
設定最大併發數量maxConcurrentOperationCount = -1
,不進行限制,併發執行maxConcurrentOperationCount = 1
,序列佇列,序列執行maxConcurrentOperationCount > 1
,併發佇列,併發執行maxConcurrentOperationCount = 0
,不會執行
注:
- 同一時間最多有多少個任務可以執行
- 序列執行並不是只開一條執行緒,它只是執行緒同步,區別序列還是並行,不是看它開了多少條執行緒,而是看任務的執行方式,是有序的還是無序的
示例:(設定最大併發數為1,佇列為序列執行任務) ```js NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//最大併發數設定為1 queue.maxConcurrentOperationCount = 1;
[queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2]; NSLog(@"1-- %@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2]; NSLog(@"2-- %@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2]; NSLog(@"3-- %@",[NSThread currentThread]); }]; ``` log:(執行緒為多條,但是屬於執行緒同步)
示例:(設定最大併發數為2,佇列為序列執行任務)
```js NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//最大併發數設定為1 queue.maxConcurrentOperationCount = 2;
[queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2]; NSLog(@"1-- %@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2]; NSLog(@"2-- %@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2]; NSLog(@"3-- %@",[NSThread currentThread]); }]; ``` log:(執行緒為多條,非同步執行,不管加入佇列有多少操作,實際佇列併發數為2)
佇列的暫停和恢復以及取消
-
暫停和恢復佇列
- 暫停表示不繼續執行佇列中的下一個任務,暫停是可以恢復的
- 佇列中的任務也是有狀態的,分為:已經執行完畢、正在執行、排隊等待狀態
- 不能暫停當前正在處於執行狀態的任務
js //暫停 queue.suspended = YES; //恢復 queue.suspended = NO;
-
取消佇列的所有操作
- 取消佇列裡所有的操作
- 取消之後,當前正在執行的操作的下一個操作將不再執行
- 取消操作是不可恢復的
- 已經取消操作,再次啟動需要重新加入佇列
js [queue cancelAllOperations]
示例:
建立佇列並執行
```js
- (void)touchesBegan:(NSSet
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-1--%@",[NSThread currentThread]);
}];
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-2--%@",[NSThread currentThread]);
}];
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-3--%@",[NSThread currentThread]);
}];
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-4--%@",[NSThread currentThread]);
}];
}
//暫停和恢復佇列 - (void)suspendedClick:(id)sender { if(self.queue.suspended){ //恢復佇列,繼續執行 self.queue.suspended = NO; }else{ //掛起(暫停佇列) self.queue.suspended = YES; } }
//取消佇列 - (void)cancelClick:(id)sender { [self.queue cancelAllOperations]; } ```
設定佇列操作依賴
NSOperation
之間可以設定依賴來保證執行順序,比如A執行完之後再執行B,就可以使用設定依賴- 設定依賴
js [op1 addDependency:op3];
- 取消依賴
js [op1 removeDependency:op3];
- 不可以迴圈依賴
js [op1 addDependency:op3]; [op3 addDependency:op1];
- 設定監聽:監聽一個操作的執行完畢
js [op2 setCompletionBlock:^{ NSLog(@"2執行完成"); }];
示例:
```js NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1---%@",[NSThread currentThread]); }];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2---%@",[NSThread currentThread]); }];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"3---%@",[NSThread currentThread]); }];
//設定依賴(op1和op3執行完之後才執行2) [op1 addDependency:op3]; [op2 addDependency:op1];
[queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3];
//監聽一個操作的執行完成 [op2 setCompletionBlock:^{ NSLog(@"2執行完成"); }]; ``` log:(依賴可知優先順序:op3 > op1 > op2,監聽的操作不一定和被監聽的操作同一個執行緒,都是非同步的,只是op3執行結束,肯定會執行監聽的操作)
監控NSOperation物件的屬性
isExecuting
表示任務正在執行中isFinished
表示任務已經執行完成,被取消也算執行完成isCancelled
表示任務已經取消執行isAsynchronous
表示任務是併發還是同步執行isReady
表示任務是併發還是同步執行
佇列裡的優先順序
- iOS8以前,
NSOperation
通過設定queuePriority
屬性來設定優先順序 - iOS 8.0後,
NSOperation
通過設定qualityOfService
來設定優先順序 - 優先順序高的先執行,低的後執行 ```js //iOS8以前的優先順序(queuePriority) typedef NS_ENUM(NSInteger, NSOperationQueuePriority) { NSOperationQueuePriorityVeryLow = -8L, NSOperationQueuePriorityLow = -4L, NSOperationQueuePriorityNormal = 0, NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8 };
//iOS8以後的優先順序(qualityOfService) typedef NS_ENUM(NSInteger, NSQualityOfService) { NSQualityOfServiceUserInteractive = 0x21,//最高優先順序,用於使用者互動事件 NSQualityOfServiceUserInitiated = 0x19,//次高優先順序,用於使用者需要馬上執行的事件 NSQualityOfServiceUtility = 0x11,//預設優先順序,主執行緒和沒有設定優先順序的執行緒都預設為這個優先順序 NSQualityOfServiceBackground = 0x09,//普通優先順序,用於普通任務 NSQualityOfServiceDefault = -1//最低優先順序,用於不重要的任務 } ```
```js NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"down1---%@",[NSThread currentThread]); }]; NSBlockOperation op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"down2---%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"down3---%@",[NSThread currentThread]);
}];
//設定優先順序 op3.qualityOfService = NSQualityOfServiceUserInteractive;
[queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3]; ``` log:
- iOS-螢幕適配(基礎概念)
- Web 開發模式
- Node.js - 在 express 中啟用 cors 跨域資源共享
- 簡單的HTTP協議
- iOS中的Storyboard
- iOS中載入xib
- iOS中自定義view的封裝
- iOS中的事件
- iOS中的定時器(GCD定時器)
- iOS中的定時器(CADisplayLink)
- iOS中的執行緒鎖(關於NSRecursiveLock)
- iOS中的執行緒鎖(關於NSConditionLock)
- iOS中的執行緒鎖(執行緒鎖的相關概念)
- iOS中的多執行緒(多執行緒的競爭)
- iOS中的多執行緒(關於NSOperationQueue)
- iOS中的多執行緒(關於NSOperation)
- iOS中的多執行緒(關於GCD訊號量)
- iOS中的多執行緒(關於GCD的其他方法)
- iOS中的多執行緒(關於GCD 的佇列組)
- iOS中的多執行緒(關於GCD的佇列和任務)