1.NSOperation,NSOperationQueue 简介

NSOperation,NSOperationQueue是苹果提供给我们的一套多线程解决方案。实际上 NSOperation、NSOperationQueue 是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。

为什么使用NSOperation NSoperationQueue

1.可以添加完整的代码块 在操作完成后执行

2.添加操作之间的依赖关系 方便的控制执行顺序

3.设定操作执行的优先级

4.可以很方便的取消一个操作的执行

5.使用KVO观察对操作执行状态的更改:isExecuteing、isFinished、isCancelled

二 NSOperation NSOperationQueue 操作和操作队列

既然是基于GCD的更高一层的封装。那么,GCD中的一些概念同样适用于NSOperation,NSOperationQueue。在NSoperation和NSOPerationQUeue中也有类似的任务(操作)和队列(操作队列)的概念。

操作

执行操作的意思 换句话说就是你在线程中执行的那段代码

在GCD中是放在Block中执行的。在NSoperation中 我们使用 NSOperation 子类 NSInvocationOperationNSBlockOperation,或者自定义子类来封装操作。

操作队列

这里的队列指操作队列 即用来存放操作的队列 不同于GCD中的调度队列FIFO(先进先出)的原则 NSOperationQueue 对于添加到队列中的操作,首先进入准备就绪的状态(就绪状态取决于操作之间的依赖关系),然后进入就绪状态的操作的开始执行顺序(非结束执行顺序)由操作之间相对的优先级决定(优先级是操作对象自身的属性)。

操作队列通过设置最大并发操作数(maxConcurrentOperationCount)来控制并发、串行。

NSOperationQueue 为我们提供了两种不同类型的队列:主队列和自定义队列。主队列运行在主线程之上,而自定义队列在后台执行。

三 NSOperation NSOperationQueue 的使用步骤

NSOperation需要配合NSOperationQueue 来实现多线程。因为默认情况下NSOperation 单独使用时系统同步执行操作,配合 NSOperationQueue 我们能更好的实现异步执行。

NSOPeration 实现多线程的使用步骤分为三步:

1.创建操作:先将需要执行的操作封装到一个NSOperation对象中

2.创建队列:创建NSOperationQueue 对象

3.将操作加入到队列中:将NSOperation对象添加到NS OperationQueue对象中

之后 系统就会自动将NSOperationQueue 中的 NSOperation 取出来,在新线程中执行操作。

四 NSOPeration的使用

不添加到NSOPerationQueue 中 只封装操作的时候

- (void)blockOPeration {
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op1 --- %@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op2 --- %@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op3 --- %@",[NSThread currentThread]);
}]; //追加任务
/*
*如果没加入到队列中 默认是在主线程中执行的 但是如果一个操作中添加了多个任务(任务数量大于1) 会开启线程执行
    但不一定是子线程 有可能是主线程 NSInvocationOperation也是这种情况
*/
[op3 addExecutionBlock:^{
NSLog(@"op4 ---- %@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"op5 ---- %@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"op6 ---- %@",[NSThread currentThread]);
}]; [op1 start];
[op2 start];
[op3 start];
}
2018-03-08 23:05:43.358904+0800 NSOperationDemo[899:52772] op1 --- <NSThread: 0x60c000066e80>{number = 1, name = main}
2018-03-08 23:05:43.359121+0800 NSOperationDemo[899:52772] op2 --- <NSThread: 0x60c000066e80>{number = 1, name = main}
2018-03-08 23:05:43.359699+0800 NSOperationDemo[899:52772] op5 ---- <NSThread: 0x60c000066e80>{number = 1, name = main}
2018-03-08 23:05:43.359701+0800 NSOperationDemo[899:52966] op3 --- <NSThread: 0x60000007df40>{number = 3, name = (null)}
2018-03-08 23:05:43.359714+0800 NSOperationDemo[899:53301] op4 ---- <NSThread: 0x60000007de00>{number = 4, name = (null)}
2018-03-08 23:05:43.359719+0800 NSOperationDemo[899:53306] op6 ---- <NSThread: 0x604000079840>{number = 5, name = (null)}

NSOperationQueue 的使用

- (void)invocationOPerationWithQueue {
//创建操作 封装任务
//第一个参数 目标对象 self
//第二个参数 调用方法的名称
//第三个参数 前面方法需要接受的参数
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil];
NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task3) object:nil];
//创建队列
/*
GCD
串行队列 crate & 主队列
并发队列 create & 全局并发队列
NSOperation:
主队列 [NSOperationQueue mainQueue]; 是串行队列
非主队列 [[NSOperationQueue alloc] init]; 同时具备了 串行队列和并发队列的功能
默认情况下 非主队列是一个并发队列
可通过最大并发操作数(maxConcurrentOperationCount)来控制并发、串行
maxConcurrentOperationCount = 1时 只会开启一条线程 任务多时 就是串行执行
*/
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];//内部已经调用了Start方法
[queue addOperation:operation2];
[queue addOperation:operation3];
} - (void)task1 {
NSLog(@"task1 %@",[NSThread currentThread]);
}
- (void)task2 {
NSLog(@"task2 %@",[NSThread currentThread]);
}
- (void)task3 {
NSLog(@"task3 %@",[NSThread currentThread]);
}

NSBlockOPeration的使用

- (void)blockOPerationWithQueue {
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op1 --- %@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op2 --- %@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op3 --- %@",[NSThread currentThread]);
}];
//创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
//简便方法
[queue addOperationWithBlock:^{
NSLog(@"op4 ---- %@",[NSThread currentThread]);
}];

自定义NSOperation

适用于任务比较庞大 代码比较复杂 可把任务抽出来写 有利于代码隐蔽 有利于提高代码的复用性

#import "LFOperation.h"

@implementation LFOperation
//告知要执行的任务是什么
- (void)main {
NSLog(@"main --- %@",[NSThread currentThread]);
} @end
viewController
- (void)lfoperation {
LFOperation *op1 = [[LFOperation alloc] init];
LFOperation *op2 = [[LFOperation alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
[queue addOperation:op2];
}

其他用法

最大并发数

//控制队列是串行队列还是并发队列
- (void)test {
//创建队列
//默认是并发队列
self.queue = [[NSOperationQueue alloc] init];
//设置最大并发数(同一时间最多有多少个操作可以执行) 所以如果最大并发数设置为1 就是串行队列(任务按顺序执行)但是串行执行任务不等于只开启一条线程比如互斥锁
//如果等于零 不会执行任务 默认值是-1表示不受限制
self.queue.maxConcurrentOperationCount = ;
//封装操作
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op1--- %@",[NSThread currentThread]);
}];
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op2--- %@",[NSThread currentThread]);
}];
NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op3--- %@",[NSThread currentThread]);
}];
NSOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op4--- %@",[NSThread currentThread]);
}];
NSOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op5--- %@",[NSThread currentThread]);
}];
NSOperation *op6 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op6--- %@",[NSThread currentThread]);
}]; [self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
[self.queue addOperation:op4];
[self.queue addOperation:op5];
[self.queue addOperation:op6]; }

暂停 取消 开始 继续

- (IBAction)start:(id)sender {
//创建队列
//默认是并发队列
self.queue = [[NSOperationQueue alloc] init];
self.queue.maxConcurrentOperationCount = ;
//封装操作
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = ; i < ; i ++) {
NSLog(@"op1--- %@",[NSThread currentThread]);
} }];
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = ; i < ; i ++) {
NSLog(@"op2--- %@",[NSThread currentThread]);
} }];
NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = ; i < ; i ++) {
NSLog(@"op3--- %@",[NSThread currentThread]);
} }];
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
} - (IBAction)pause:(id)sender {
//暂停是可以继续的 但是不能暂停当前正在处于执行状态的任务 要等到当前正在执行状态的任务完成之后才能暂停
//队列中的任务也是有状态的
/*
已经执行的 | 正在执行的 | 处于排队等待状态的
*/
[self.queue setSuspended:YES];
} - (IBAction)goon:(id)sender {
[self.queue setSuspended:NO];
} - (IBAction)cancel:(id)sender {
//取消 是不可以恢复的 也是把当前任务执行完毕以后 取消后面的任务 内部调用了所有任务的cancel方法
[self.queue cancelAllOperations];
}

但是自定义的写在main 函数里面的操作 即使是多个也会被认为是一个任务 所以暂停 取消 继续没什么效果 但是可以这样判断使取消任务有作用 仅限于取消

//告知要执行的任务是什么
- (void)main { for (NSInteger i = ; i < ; i ++) {
NSLog(@"op1--- %@",[NSThread currentThread]);
}
if (self.isCancelled) {
return;
} for (NSInteger i = ; i < ; i ++) {
NSLog(@"op2--- %@",[NSThread currentThread]);
}
if (self.isCancelled) {
return;
}
for (NSInteger i = ; i < ; i ++) {
NSLog(@"op3--- %@",[NSThread currentThread]);
}
}

NSOperation 添加操作依赖和监听

依赖

- (void)yilai {
//创建队列
//默认是并发队列
self.queue = [[NSOperationQueue alloc] init];
//封装操作
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op1--- %@",[NSThread currentThread]);
}];
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op2--- %@",[NSThread currentThread]);
}];
NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op3--- %@",[NSThread currentThread]);
}];
NSOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op4--- %@",[NSThread currentThread]);
}];
//添加操作依赖
//注意 不能循环依赖 否则会出现相互等待 相互依赖的两个操作谁都不会执行
//不同队列中的不同操作也可以设置依赖关系(跨队列依赖)
[op1 addDependency:op4];//操作一 依赖于操作4 操作4先于操作一执行
[op4 addDependency:op3];
[op3 addDependency:op2];
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
[self.queue addOperation:op4];
}

监听

- (void)jianting {
//创建队列
//默认是并发队列
self.queue = [[NSOperationQueue alloc] init];
//封装操作
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op1--- %@",[NSThread currentThread]);
}];
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op2--- %@",[NSThread currentThread]);
}];
NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op3--- %@",[NSThread currentThread]);
}];
NSOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"op4--- %@",[NSThread currentThread]);
}];
//添加监听
op3.completionBlock = ^{
NSLog(@"op3 已经完成 %@",[NSThread currentThread]);
}; //添加操作依赖
//注意 不能循环依赖 否则会出现相互等待 相互依赖的两个操作谁都不会执行
//不同队列中的不同操作也可以设置依赖关系(跨队列依赖)
[op1 addDependency:op4];//操作一 依赖于操作4 操作4先于操作一执行
[op4 addDependency:op3];
[op3 addDependency:op2];
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
[self.queue addOperation:op4];

线程间的通信

- (void)downLoadImage {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"&&&&&"]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//主线程更新UI
[NSOperationQueue.mainQueue addOperationWithBlock:^{
self.imageView.image = image;
}]; }];
[queue addOperation:op1];
}

iOS 多线程之 NSOperation 的基本使用的更多相关文章

  1. iOS多线程编程--NSOperation(转)

    这篇文章写得非常不错,基础用法都涉及到了,我把文章提到的例子都写到了demo里面, 原文地址: iOS多线程--彻底学会多线程之『NSOperation』 demo下载:https://github. ...

  2. IOS多线程(NSOperation,NSOperationQueue)

    含义:NSOperation,NSOperationQueue是什么. The NSOperation class is an abstract class you use to encapsulat ...

  3. iOS开发多线程篇—NSOperation简单介绍

    iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...

  4. iOS开发多线程篇—NSOperation基本操作

    iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. ...

  5. iOS 多线程学习笔记 —— NSOperation

    本文复制.参考自文章:iOS多线程编程之NSOperation和NSOperationQueue的使用 ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://b ...

  6. [转] iOS多线程编程之NSOperation和NSOperationQueue的使用

    <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...

  7. iOS多线程开发之NSOperation - 快上车,没时间解释了!

    一.什么是NSOperation? NSOperation是苹果提供的一套多线程解决方案.实际上NSOperation是基于GCD更高一层的封装,但是比GCD更加的面向对象.代码可读性更高.可控性更强 ...

  8. iOS 多线程 简单学习NSThread NSOperation GCD

    1:首先简单介绍什么叫线程 可并发执行的,拥有最小系统资源,共享进程资源的基本调度单位. 共用堆,自有栈(官方资料说明iOS主线程栈大小为1M,其它线程为512K). 并发执行进度不可控,对非原子操作 ...

  9. iOS多线程编程之NSOperation和NSOperationQueue的使用

    前一篇 <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是 ...

随机推荐

  1. 【BIEE】14_开发流程介绍

    以上是BIEE开发的流程图,通过流程图我们可以看出在BIEE中存在以下主要内容: 仪表盘 仪表盘页 分析 仪表盘提示 主题区域 Catalog RPD 以下是一些文件以及资料库存储路径 资料库存储路径 ...

  2. iOS 自定义转场动画

    代码地址如下:http://www.demodashi.com/demo/12955.html 一.总效果 本文记录分享下自定义转场动画的实现方法,具体到动画效果:新浪微博图集浏览转场效果.手势过渡动 ...

  3. hdu3415 Max Sum of Max-K-sub-sequence 单调队列

    //hdu3415 Max Sum of Max-K-sub-sequence //单调队列 //首先想到了预处理出前缀和利用s[i] - s[j]表示(j,i]段的和 //之后的问题就转换成了求一个 ...

  4. Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构

    Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构 1. 索引的分类1 1.1. 索引的类型  按查找方式分,两种,分块索引 vs编号索引1 1.2. 按索引与数据的查找顺序可分为 正 ...

  5. VS项目名称修改

    阅读数:11141 VS中新建一个项目,如果开发工作都接近尾声,客户来要求更换项目的名称,差不多要变更整个解决方案中项目名称,引用等等,这个工作量还是很大的.上网搜索解决方法,还实验了专门的修改项目名 ...

  6. Android JNI和NDK学习(04)--NDK调试方法(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3092812.html 本文主要介绍在ndk中添加log的方法.然后,我们就可 ...

  7. iOS- 详解文本属性Attributes(转)

    iOS- 详解文本属性Attributes 1.NSKernAttributeName: @10 调整字句 kerning 字句调整 2.NSFontAttributeName : [UIFont s ...

  8. MFC 点击按钮,弹出另一个对话框(模态及非模态对话框)

    1. 模态对话框 资源视图->Dialog->右键->添加资源->新建->对话框->右键->添加类. 例如:在A_dialog中点击按钮弹出B_dialog  ...

  9. 百度UEditor 用require 引入 Thinkphp5 ,图片上传问题

    用require引入,用了10分钟:上传图片,用了一个早上(吐血一地.....) 重点:require引入成功后,在需要引用UEditor的文件开头加入(ue的文件夹路径) window.UEDITO ...

  10. Spring MVC简单URL处理程序映射

    以下示例显示如何使用Spring Web MVC框架来实现一个简单URL处理程序映射. SimpleUrlHandlerMapping类分别显式地将URL映射到相应的控制器上. 所下所示配置 - &l ...