NSOperation
NSOperation簡介
-
Operation: 操作的意思. - 是OC語言中
基于GCD的面向?qū)ο蟮姆庋b. - 使用起來比GCD更加簡單(面向?qū)ο螅?/li>
- 提供了一些用GCD不好實(shí)現(xiàn)的功能.
- 蘋果推薦使用,使用NSOperation不用關(guān)心線程以及線程的生命周期.

GCD和OP的關(guān)系圖.png
NSOperation類的介紹
-
NSOperation是個(gè)抽象類,無法直接使用.因?yàn)榉椒ㄖ挥新暶鳑]有實(shí)現(xiàn).作為父類使用的.約束子類共有的屬性和方法.
-
子類 :
NSInvocationOperationNSBlockOperation- 自定義
NSOperation
操作默認(rèn)是
異步的. -
隊(duì)列 :
NSOperationQueue隊(duì)列默認(rèn)是
并發(fā)的. -
核心 :
- GCD的核心 : 將
任務(wù)添加到隊(duì)列中 - OP的核心 : 將
操作添加到隊(duì)列中
- GCD的核心 : 將
使用步驟
- 先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對象中.創(chuàng)建NSOperation對象.
- 將NSOperation對象添加到NSOperationQueue中.
- NSOperationQueue會(huì)自動(dòng)將NSOperation取出來.
- 將取出的NSOperation封裝的操作自動(dòng)放到一條對應(yīng)的新線程中執(zhí)行.

操作添加到隊(duì)列.png
NSInvocationOperation
- 核心 : 將
操作添加到隊(duì)列.
NSInvocationOperation 基本使用演練
- (void)demo:(id)parram
{
// 查看當(dāng)前線程
NSLog(@"%@ %@",parram,[NSThread currentThread]);
}
OP調(diào)用start方法
- (void)opDemo1
{
// 創(chuàng)建操作對象
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"InvocationOperation"];
// 調(diào)用start方法
[op start];
}
-
[op start];方法,會(huì)在當(dāng)前線程執(zhí)行@selector方法.
NSInvocationOperation 將操作添加到隊(duì)列
- (void)opDemo2
{
// 操作對象 : OP中的操作對象默認(rèn)是異步執(zhí)行
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"InvocationOperation"];
// 隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 將操作添加到隊(duì)列
[queue addOperation:op];
}
-
操作: 默認(rèn)是異步執(zhí)行.
NSInvocationOperation 驗(yàn)證隊(duì)列并發(fā)性
- (void)opDemo3
{
// 隊(duì)列 : 默認(rèn)是并發(fā)的
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 循環(huán)的向隊(duì)列中添加10個(gè)操作
for (int i = 0; i < 10; i++) {
// 操作對象 : OP中的操作對象默認(rèn)是異步執(zhí)行
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@(i)];
// 將操作添加到隊(duì)列
[queue addOperation:op];
}
}
- 執(zhí)行效果 : 會(huì)開啟多條線程,不是順序執(zhí)行.與GCD中并發(fā)隊(duì)列&異步執(zhí)行效果一樣
-
隊(duì)列: 默認(rèn)是并發(fā)的
NSBlockOperation
NSBlockOperation 基本使用演練
NSBlockOperation 操作添加到隊(duì)列
- (void)opDemo1
{
// 隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 操作 : 默認(rèn)是異步的
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 查看當(dāng)前線程
NSLog(@"%@",[NSThread currentThread]);
}];
// 將操作添加到隊(duì)列
[queue addOperation:op];
// 在當(dāng)前線程執(zhí)行
// [op start];
}
NSBlockOperation 驗(yàn)證隊(duì)列并發(fā)性
- (void)opDemo2
{
// 隊(duì)列 : 默認(rèn)是并發(fā)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for (int i = 0; i < 10; i++) {
// 操作 : 默認(rèn)是異步的
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 查看當(dāng)前線程
NSLog(@"%d %@",i,[NSThread currentThread]);
}];
// 將操作添加到隊(duì)列
[queue addOperation:op];
}
}
開發(fā)建議
- NSOperationQueue只有一種類型.就是并發(fā)隊(duì)列.
- 在實(shí)際開發(fā)時(shí),如果要使用到NSOperationQueue,可以直接定義成全局的隊(duì)列
/// 定義全局隊(duì)列
@property (nonatomic,strong) NSOperationQueue *queue;
- (NSOperationQueue *)queue
{
if (_queue==nil) {
_queue = [[NSOperationQueue alloc] init];
}
return _queue;
}
NSBlockOperation 簡寫
- (void)opDemo3
{
[self.queue addOperationWithBlock:^{
// 查看當(dāng)前線程
NSLog(@"%@",[NSThread currentThread]);
}];
}
線程間通信
- (void)opDemo5
{
[self.queue addOperationWithBlock:^{
NSLog(@"努力下載中...%@",[NSThread currentThread]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"更新UI...%@",[NSThread currentThread]);
}];
}];
}
NSOperation與GCD對比
GCD
- 核心概念 : 將
任務(wù)(block)添加到隊(duì)列(串行/并發(fā)/主隊(duì)列),并且指定任務(wù)執(zhí)行的函數(shù)(同步/異步). - GCD是C語言的API.
-
iOS 4.0推出的,針對多核處理器的并發(fā)技術(shù). - 任務(wù)封裝在
block中. - 要停止已經(jīng)加入
隊(duì)列(queue)的任務(wù)(block)需要寫復(fù)雜的代碼. - 只能設(shè)置隊(duì)列的優(yōu)先級.
- 建立任務(wù)間的依賴關(guān)系比較復(fù)雜.
-
高級功能 :
- 一次性 once
- 延遲操作 after
- 調(diào)度組
NSOperation
- 核心概念:把
操作(異步)添加到隊(duì)列(并發(fā)隊(duì)列) - OC 框架,更加面向?qū)ο?,是?GCD 的封裝.
-
iOS 2.0推出的,蘋果推出 GCD 之后,對NSOperation的底層全部重寫 - 任務(wù)封裝在
Operation對象中的,為我們提供了更多的選擇.操作對象更加方便. - 可以取消掉隊(duì)列中的任務(wù),正在執(zhí)行的任務(wù)除外.
- 可以設(shè)置隊(duì)列中每一個(gè)操作的優(yōu)先級.
- 可以跨隊(duì)列設(shè)置操作的依賴關(guān)系.
-
高級功能 :
- 最大操作并發(fā)數(shù)(GCD不好做)
- 繼續(xù)/暫停/全部取消
- 跨隊(duì)列設(shè)置操作的依賴關(guān)系
NSOperation高級功能演練
- 最大操作并發(fā)數(shù)
- 繼續(xù)/暫停/取消全部
- 操作的優(yōu)先級和監(jiān)聽操作執(zhí)行完成的回調(diào)
- 操作間依賴關(guān)系
隊(duì)列的最大并發(fā)數(shù)
- 是
隊(duì)列的一個(gè)屬性. @property NSInteger maxConcurrentOperationCount;- 限制
同時(shí)執(zhí)行的任務(wù)數(shù). - 比如,最大并發(fā)數(shù)設(shè)置成3,CPU就最多準(zhǔn)備3個(gè)線程同時(shí)執(zhí)行3個(gè)任務(wù).
- 線程可以復(fù)用.而且在線程回收的間隙可以及時(shí)的準(zhǔn)備線程保證并發(fā)性.
*** 準(zhǔn)備隊(duì)列**
/// 定義全局隊(duì)列
@property (nonatomic,strong) NSOperationQueue *queue;
- 懶加載的時(shí)候設(shè)置最大并發(fā)數(shù)
- (NSOperationQueue *)queue
{
if (_queue==nil) {
_queue = [[NSOperationQueue alloc] init];
// 設(shè)置最大并發(fā)數(shù) : 每次只能調(diào)度兩個(gè)操作執(zhí)行
_queue.maxConcurrentOperationCount = 2;
}
return _queue;
}
- 演示最大并發(fā)數(shù)對隊(duì)列調(diào)度任務(wù)的影響
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self opDemo];
}
- (void)opDemo
{
NSLog(@"start");
for (int i = 0; i < 20; i++) {
[self.queue addOperationWithBlock:^{
// 休眠一秒鐘,演示最大并發(fā)數(shù)的效果更好
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%d %@",i,[NSThread currentThread]);
}];
}
}
執(zhí)行的結(jié)果 : 任務(wù)是兩個(gè)兩個(gè)的執(zhí)行.
隊(duì)列的暫停繼續(xù)和取消全部
- 在最大并發(fā)數(shù)的代碼基礎(chǔ)上演示隊(duì)列的暫停繼續(xù)和取消全部
相關(guān)的屬性和方法介紹
-
- (BOOL)isSuspended;暫停和繼續(xù)隊(duì)列的屬性. -
YES代表暫停隊(duì)列,NO代表恢復(fù)隊(duì)列. -
cancelAllOperations: 取消隊(duì)列中的全部操作. -
cancel: 取消隊(duì)列中的單個(gè)操作.
1. 隊(duì)列暫停
#pragma mark - 演示隊(duì)列的暫停
- (IBAction)stop:(id)sender
{
// 暫停隊(duì)列之前判斷隊(duì)列中有無操作
if (self.queue.operationCount == 0) {
return;
}
// 暫停隊(duì)列
self.queue.suspended = YES;
NSLog(@"暫停 %zd",self.queue.operationCount);
}
- 將隊(duì)列掛起之后,隊(duì)列中的操作就不會(huì)被調(diào)度,但是正在執(zhí)行的操作不受影
-
operationCount:操作計(jì)數(shù),沒有執(zhí)行和沒有執(zhí)行完的操作,都會(huì)計(jì)算在操作計(jì)數(shù)之內(nèi)
注意 : 如果先暫停隊(duì)列,再添加操作到隊(duì)列,隊(duì)列不會(huì)調(diào)度添加的操作.所以在暫停隊(duì)列之前要判斷隊(duì)列中有沒有任務(wù).如果沒有任務(wù)就不暫停隊(duì)列.
2. 隊(duì)列繼續(xù)
- (IBAction)resume:(id)sender
{
// 隊(duì)列繼續(xù)
self.queue.suspended = NO;
NSLog(@"繼續(xù) %zd",self.queue.operationCount);
}
3. 隊(duì)列取消全部
- (IBAction)cancelAll:(id)sender
{
[self.queue cancelAllOperations];
NSLog(@"取消全部 %zd",self.queue.operationCount);
}
- 一旦調(diào)用的
cancelAllOperations方法,隊(duì)列中的操作,都會(huì)被移除,正在執(zhí)行的操作除外. - 正在執(zhí)行的操作取消不了,如果要取消,需要自定義隊(duì)列.
操作優(yōu)先級和監(jiān)聽操作完成回調(diào)
-
操作的優(yōu)先級:qualityOfService- 無法決定操作執(zhí)行的先后順序的,
決定的是操作有更多的機(jī)會(huì)被隊(duì)列調(diào)度執(zhí)行.
- 無法決定操作執(zhí)行的先后順序的,
-
監(jiān)聽操作完成的回調(diào):@property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);- 當(dāng)操作執(zhí)行結(jié)束之后,就會(huì)回調(diào),是在子線程中執(zhí)行的.
- (void)opDemo
{
// 操作1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10; i++) {
// 查看當(dāng)前線程
NSLog(@"op1 %@",[NSThread currentThread]);
}
}];
//設(shè)置操作的優(yōu)先級
op1.qualityOfService = NSQualityOfServiceUserInteractive;
// 當(dāng)操作執(zhí)行結(jié)束之后,就會(huì)回調(diào),是在子線程中執(zhí)行的
[op1 setCompletionBlock:^{
// 查看當(dāng)前線程
NSLog(@"操作結(jié)束了 %@",[NSThread currentThread]);
}];
[self.queue addOperation:op1];
// 操作2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10; i++) {
// 查看當(dāng)前線程
NSLog(@"op2 %@",[NSThread currentThread]);
}
}];
op2.qualityOfService = NSQualityOfServiceBackground;
[self.queue addOperation:op2];
}
操作間依賴
操作op2依賴于op1
[op2 addDependency:op1];
4. 操作依賴
需求 : 登陸-->付費(fèi)-->下載-->通知用戶
- 準(zhǔn)備需要執(zhí)行的操作
#pragma mark - 操作依賴
- (void)dependency
{
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"登陸 %@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"付費(fèi) %@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下載 %@",[NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"通知用戶 %@",[NSThread currentThread]);
}];
}
- 建立依賴關(guān)系 : 不能循環(huán)建立操作間依賴關(guān)系.否則,隊(duì)列不調(diào)度操作執(zhí)行
// 操作2依賴操作1
[op2 addDependency:op1];
[op3 addDependency:op2];
[op4 addDependency:op3];
// 不能循環(huán)依賴 : 操作不會(huì)被調(diào)度
// [op1 addDependency:op4];
// waitUntilFinished : 是否等到指定的操作執(zhí)行結(jié)束再執(zhí)行后面的代碼
[self.queue addOperations:@[op1,op2,op3,op4] waitUntilFinished:NO];
// 驗(yàn)證 waitUntilFinished
NSLog(@"end");
- 建立依賴關(guān)系 : 操作間可以跨隊(duì)列建立依賴關(guān)系
// 操作2依賴操作1
[op2 addDependency:op1];
[op3 addDependency:op2];
[op4 addDependency:op3];
// 不能循環(huán)依賴 : 操作不會(huì)被調(diào)度
// [op1 addDependency:op4];
// waitUntilFinished : 是否等到指定的操作執(zhí)行結(jié)束再執(zhí)行后面的代碼
[self.queue addOperations:@[op1,op2,op3] waitUntilFinished:NO];
// 通知用戶的操作在主線程中執(zhí)行
// 操作可以跨隊(duì)列依賴
[[NSOperationQueue mainQueue] addOperation:op4];
// 驗(yàn)證 waitUntilFinished
NSLog(@"end");
- 建立依賴關(guān)系 : 要將操作間的依賴建立好了之后,再添加到隊(duì)列中