NSOperation、NSOperationQueue 是蘋果提供給咱們的一套多線程解決方案。實際上NSOperation、NSOperationQueue 是基於 GCD 更高一層的封裝,徹底面向對象。可是比 GCD 更簡單易用、代碼可讀性也更高bash
爲何要使用 NSOperation、NSOperationQueue?多線程
既然是基於 GCD 的更高一層的封裝。那麼,GCD 中的一些概念一樣適用於 NSOperation、NSOperationQueue。在 NSOperation、NSOperationQueue 中也有相似的任務(操做)和隊列(操做隊列)的概念。併發
NSOperation 是個抽象類,不能用來封裝操做。咱們只有使用它的子類來封裝操做。咱們有三種方式來封裝操做。框架
/**
NSInvocationOperation : 建立操做 ---> 建立隊列 ---> 操做加入隊列
*/
- (void)demo{
//1:建立操做
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"123"];
//2:建立隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//3:操做加入隊列 --- 操做會在新的線程中
[queue addOperation:op];
}
- (void)handleInvocation:(id)op{
NSLog(@"%@ --- %@",op,[NSThread currentThread]);
}
複製代碼
打印:異步
2020-01-29 15:43:11.012492+0800 001---NSOperation初體驗[1628:78932] 123 --- <NSThread: 0x600001ea9080>{number = 3, name = (null)}
複製代碼
NSInvocationOperation也能夠手動調起,這樣不會開啓線程,會在當前隊列執行任務ui
/**
手動調起操做
*/
- (void)demo1{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"123"];
// 注意 : 若是該任務已經添加到隊列,你再手動調回出錯
// NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// [queue addOperation:op];
// 手動調起操做,默認在當前線程
[op start];
}
- (void)handleInvocation:(id)op{
NSLog(@"%@ --- %@",op,[NSThread currentThread]);
}
複製代碼
打印:spa
2020-01-29 15:52:55.404726+0800 001---NSOperation初體驗[1740:83188] 123 --- <NSThread: 0x60000024e940>{number = 1, name = main}
複製代碼
注意:咱們儘可能不要用這種方式去執行任務,若是該任務已經添加到隊列,再手動調起任務程序會崩潰線程
/**
blockOperation 初體驗
*/
- (void)demo2{
//1:建立blockOperation
NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ -- %@",[NSThread mainThread],[NSThread currentThread]);
}];
//1.1 設置監聽
bo.completionBlock = ^{
NSLog(@"完成了!!!");
};
//2:建立隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//3:添加到隊列
[queue addOperation:bo];
}
複製代碼
打印:3d
2020-01-29 15:57:30.760964+0800 001---NSOperation初體驗[1812:85696] <NSThread: 0x600001a66940>{number = 1, name = (null)} -- <NSThread: 0x600001a2dec0>{number = 3, name = (null)}
2020-01-29 15:57:30.761098+0800 001---NSOperation初體驗[1812:85697] 完成了!!!
複製代碼
NSBlockOperation也可使用start方法手動執行,這樣不會開啓線程,會在當前隊列執行任務。若是該任務已經添加到隊列中,手動調起任務程序會崩潰code
若是使用子類 NSInvocationOperation、NSBlockOperation 不能知足平常需求,咱們可使用自定義繼承自 NSOperation 的子類。
先定義一個繼承 NSOperation 的子類,重寫main方法。
// NHOperation.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NHOperation : NSOperation
@end
NS_ASSUME_NONNULL_END
// NHOperation.m
#import "NHOperation.h"
@implementation NHOperation
- (void)main{
if (!self.isCancelled) {
for (int i = 0; i < 2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"1---%@", [NSThread currentThread]);
}
}
}
@end
複製代碼
導入頭文件NHOperation.h
- (void)demo3{
NHOperation *nhQueue = [[NHOperation alloc]init];
[nhQueue start];
}
複製代碼
打印:
2020-01-29 16:20:57.036713+0800 001---NSOperation初體驗[2060:94891] 1---<NSThread: 0x600001c16940>{number = 1, name = main}
2020-01-29 16:20:59.037879+0800 001---NSOperation初體驗[2060:94891] 1---<NSThread: 0x600001c16940>{number = 1, name = main}
複製代碼
這種自定義繼承NSOperation的寫法能夠本身掌握線程的生命週期,SDWebImage框架重寫了start,main等一系列方法,去實現下載圖片模塊
/**
可執行代碼塊
*/
- (void)demo5{
//建立操做
NSBlockOperation *ob = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
//添加執行代碼塊
[ob addExecutionBlock:^{
NSLog(@"這是一個執行代碼塊 - %@",[NSThread currentThread]);
}];
// 執行代碼塊 在新的線程 建立的操做在當前線程
//[ob start];
//利用隊列,兩個都在新的線程中
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:ob];
}
複製代碼
打印:
2020-01-29 16:37:49.565971+0800 001---NSOperation初體驗[2207:101558] <NSThread: 0x600002457d40>{number = 3, name = (null)}
2020-01-29 16:37:49.565991+0800 001---NSOperation初體驗[2207:101555] 這是一個執行代碼塊 - <NSThread: 0x600002458480>{number = 4, name = (null)}
複製代碼
/**
線程通信
*/
- (void)demo6{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.name = @"Noah";
[queue addOperationWithBlock:^{
NSLog(@"%@ = %@",[NSOperationQueue currentQueue],[NSThread currentThread]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"%@ --%@",[NSOperationQueue currentQueue],[NSThread currentThread]);
}];
}];
}
複製代碼
打印:
2020-01-29 16:38:41.372075+0800 001---NSOperation初體驗[2239:102618] <NSOperationQueue: 0x6000015ee560>{name = 'Noah'} = <NSThread: 0x6000000f9880>{number = 3, name = (null)}
2020-01-29 16:38:41.378217+0800 001---NSOperation初體驗[2239:102581] <NSOperationQueue: 0x6000015ea180>{name = 'NSOperationQueue Main Queue'} --<NSThread: 0x600000086940>{number = 1, name = main}
複製代碼
/**
優先級,只會讓CPU有更高的概率調用,不是說設置高就必定所有先完成
*/
- (void)demo4{
NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10; i++) {
NSLog(@"第1個操做 %d --- %@", i, [NSThread currentThread]);
}
}];
// 設置優先級 - 最高
bo1.qualityOfService = NSQualityOfServiceUserInteractive;
//建立第二個操做
NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10; i++) {
NSLog(@"第二個操做 %d --- %@", i, [NSThread currentThread]);
}
}];
// 設置優先級 - 最低
bo2.qualityOfService = NSQualityOfServiceBackground;
//2:建立隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//3:添加到隊列
[queue addOperation:bo1];
[queue addOperation:bo2];
}
複製代碼
打印:
2020-01-29 16:42:21.830886+0800 001---NSOperation初體驗[2296:104794] 第1個操做 0 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.830901+0800 001---NSOperation初體驗[2296:104795] 第2個操做 0 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.831015+0800 001---NSOperation初體驗[2296:104794] 第1個操做 1 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831076+0800 001---NSOperation初體驗[2296:104794] 第1個操做 2 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831107+0800 001---NSOperation初體驗[2296:104795] 第2個操做 1 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.831135+0800 001---NSOperation初體驗[2296:104794] 第1個操做 3 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831217+0800 001---NSOperation初體驗[2296:104794] 第1個操做 4 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831241+0800 001---NSOperation初體驗[2296:104795] 第2個操做 2 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.831306+0800 001---NSOperation初體驗[2296:104794] 第1個操做 5 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831351+0800 001---NSOperation初體驗[2296:104795] 第2個操做 3 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.831387+0800 001---NSOperation初體驗[2296:104794] 第1個操做 6 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831438+0800 001---NSOperation初體驗[2296:104795] 第2個操做 4 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.831595+0800 001---NSOperation初體驗[2296:104794] 第1個操做 7 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831771+0800 001---NSOperation初體驗[2296:104794] 第1個操做 8 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.831957+0800 001---NSOperation初體驗[2296:104795] 第2個操做 5 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.834469+0800 001---NSOperation初體驗[2296:104794] 第1個操做 9 --- <NSThread: 0x6000003f7200>{number = 3, name = (null)}
2020-01-29 16:42:21.834487+0800 001---NSOperation初體驗[2296:104795] 第2個操做 6 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.834579+0800 001---NSOperation初體驗[2296:104795] 第2個操做 7 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.834659+0800 001---NSOperation初體驗[2296:104795] 第2個操做 8 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
2020-01-29 16:42:21.834761+0800 001---NSOperation初體驗[2296:104795] 第2個操做 9 --- <NSThread: 0x600000384a80>{number = 4, name = (null)}
複製代碼
- (void)demo7{
NSOperationQueue *queue = [NSOperationQueue new];
// 設置隊列最大併發數爲2
queue.maxConcurrentOperationCount = 2;
for (int i = 0; i<10; i++) {
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"%d-%@",i,[NSThread currentThread]);
}];
}
}
複製代碼
打印:
2020-01-29 16:45:11.512510+0800 001---NSOperation初體驗[2360:107175] 0-<NSThread: 0x6000023c2140>{number = 3, name = (null)}
2020-01-29 16:45:11.512505+0800 001---NSOperation初體驗[2360:107173] 1-<NSThread: 0x6000023d1280>{number = 4, name = (null)}
2020-01-29 16:45:13.514845+0800 001---NSOperation初體驗[2360:107172] 2-<NSThread: 0x6000023c4980>{number = 5, name = (null)}
2020-01-29 16:45:13.514883+0800 001---NSOperation初體驗[2360:107174] 3-<NSThread: 0x6000023fc380>{number = 6, name = (null)}
2020-01-29 16:45:15.516537+0800 001---NSOperation初體驗[2360:107173] 4-<NSThread: 0x6000023d1280>{number = 4, name = (null)}
2020-01-29 16:45:15.516537+0800 001---NSOperation初體驗[2360:107172] 5-<NSThread: 0x6000023c4980>{number = 5, name = (null)}
2020-01-29 16:45:17.518188+0800 001---NSOperation初體驗[2360:107173] 7-<NSThread: 0x6000023d1280>{number = 4, name = (null)}
2020-01-29 16:45:17.518188+0800 001---NSOperation初體驗[2360:107174] 6-<NSThread: 0x6000023fc380>{number = 6, name = (null)}
2020-01-29 16:45:19.521176+0800 001---NSOperation初體驗[2360:107172] 8-<NSThread: 0x6000023c4980>{number = 5, name = (null)}
2020-01-29 16:45:19.521176+0800 001---NSOperation初體驗[2360:107174] 9-<NSThread: 0x6000023fc380>{number = 6, name = (null)}
複製代碼
- (void)demo{
NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"請求token");
}];
NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"拿着token,請求數據1");
}];
NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"拿着數據1,請求數據2");
}];
//由於異步,很差控制,咱們藉助依賴
[bo2 addDependency:bo1];
[bo3 addDependency:bo2];
//注意這裏必定不要構成循環依賴 : 不會報錯,可是全部操做不會執行
//[bo1 addDependency:bo3];
//waitUntilFinished 堵塞線程
[self.queue addOperations:@[bo1,bo2,bo3] waitUntilFinished:NO];
NSLog(@"執行完了?我要幹其餘事");
}
複製代碼
打印:
2020-01-29 16:47:41.371621+0800 002---NSOperation深刻淺出[2422:109106] 執行完了?我要幹其餘事
2020-01-29 16:47:41.872960+0800 002---NSOperation深刻淺出[2422:109157] 請求token
2020-01-29 16:47:42.374790+0800 002---NSOperation深刻淺出[2422:109156] 拿着token,請求數據1
2020-01-29 16:47:42.877750+0800 002---NSOperation深刻淺出[2422:109156] 拿着數據1,請求數據2
複製代碼
/**
關於operationQueue的掛起,繼續,取消
*/
- (void)demo1{
self.queue.name = @"Cooci";
self.queue.maxConcurrentOperationCount = 2;
for (int i=0; i< 20; i++) {
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%@-----%d",[NSThread currentThread],i);
}];
}
}
- (IBAction)pauseOrContinue:(id)sender {
if (self.queue.operationCount == 0) {
NSLog(@"當前沒有操做,沒有必要掛起和繼續");
return;
}
// 一個細節 正在執行的操做沒法掛起
if (self.queue.suspended) {
NSLog(@"當前是掛起狀態,準備繼續");
}else{
NSLog(@"當前爲執行狀態,準備掛起");
}
self.queue.suspended = !self.queue.isSuspended;
}
- (IBAction)cancel:(id)sender {
[self.queue cancelAllOperations];
}
複製代碼
打印:
2020-01-29 16:52:44.854415+0800 002---NSOperation深刻淺出[2488:112001] <NSThread: 0x600001d57180>{number = 3, name = (null)}-----1
2020-01-29 16:52:44.854415+0800 002---NSOperation深刻淺出[2488:111998] <NSThread: 0x600001d1da40>{number = 4, name = (null)}-----0
2020-01-29 16:52:45.856950+0800 002---NSOperation深刻淺出[2488:111999] <NSThread: 0x600001d1f080>{number = 5, name = (null)}-----2
2020-01-29 16:52:45.856988+0800 002---NSOperation深刻淺出[2488:112000] <NSThread: 0x600001d04280>{number = 6, name = (null)}-----3
2020-01-29 16:52:46.277210+0800 002---NSOperation深刻淺出[2488:111955] 當前爲執行狀態,準備掛起
2020-01-29 16:52:46.857767+0800 002---NSOperation深刻淺出[2488:112001] <NSThread: 0x600001d57180>{number = 3, name = (null)}-----4
2020-01-29 16:52:46.857782+0800 002---NSOperation深刻淺出[2488:111999] <NSThread: 0x600001d1f080>{number = 5, name = (null)}-----5
2020-01-29 16:52:48.967113+0800 002---NSOperation深刻淺出[2488:111955] 當前是掛起狀態,準備繼續
2020-01-29 16:52:49.968072+0800 002---NSOperation深刻淺出[2488:112001] <NSThread: 0x600001d57180>{number = 3, name = (null)}-----6
2020-01-29 16:52:49.968087+0800 002---NSOperation深刻淺出[2488:111999] <NSThread: 0x600001d1f080>{number = 5, name = (null)}-----7
2020-01-29 16:52:50.969946+0800 002---NSOperation深刻淺出[2488:112000] <NSThread: 0x600001d04280>{number = 6, name = (null)}-----8
2020-01-29 16:52:50.969946+0800 002---NSOperation深刻淺出[2488:112001] <NSThread: 0x600001d57180>{number = 3, name = (null)}-----9
2020-01-29 16:52:51.465420+0800 002---NSOperation深刻淺出[2488:111955] 所有取消
2020-01-29 16:52:51.973286+0800 002---NSOperation深刻淺出[2488:111999] <NSThread: 0x600001d1f080>{number = 5, name = (null)}-----10
2020-01-29 16:52:51.973297+0800 002---NSOperation深刻淺出[2488:112001] <NSThread: 0x600001d57180>{number = 3, name = (null)}-----11
複製代碼