iOS开发——多线程篇——NSOperation(基于GCD多线程编程),下载图片并合成新图片
一、NSOperation的基本概念
1、简介
NSOperation的作用
配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤
先将需要执行的操作封装到一个NSOperation对象中
然后将NSOperation对象添加到NSOperationQueue中
系统会自动将NSOperationQueue中的NSOperation取出来
将取出的NSOperation封装的操作放到一条新线程中执行
2、NSOperation的子类
NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
使用NSOperation子类的方式有3种
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法
二、NSOperation的具体使用
1、NSInvocationOperation
创建NSInvocationOperation对象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
调用start方法开始执行操作
- (void)start;
一旦执行操作,就会调用target的sel方法
// 1.将操作封装到Operation中
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
// 2.执行封装的操作
// 如果直接执行NSInvocationOperation中的操作, 那么默认会在主线程中执行
[op1 start];
注意
默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
2、创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
// 1.封装操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1- %@", [NSThread currentThread]);
}]; // 2.添加操作
[op1 addExecutionBlock:^{
NSLog(@"2- %@", [NSThread currentThread]);
}];
[op1 addExecutionBlock:^{
NSLog(@"3- %@", [NSThread currentThread]);
}]; // 2.执行操作
// 如果只封装了一个操作, 那么默认会在主线程中执行
// 如果封装了多个操作, 那么除了第一个操作以外, 其它的操作会在子线程中执行
[op1 start];
注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
3、自定义子类继承NSOperation
// 1.封装操作
// 如果是自定义类继承于NSOperation, 那么需要将操作写到自定义类的main方法中
// 这种实现方式, 可以提高代码的复用性
CHGOperation *op1 = [[CHGOperation alloc] init];
// 2.执行操作
[op1 start];
三、NSOperationQueue
1、简介
NSOperationQueue的作用
NSOperation可以调用start方法来执行任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
/*
GCD队列:
串行: 自己创建, 主队列
并发: 自己创建, 全局 NSOperationQueue:
自己创建: alloc/init --> 默认是并发 --> 也可以让它串行
主队列 : mainQueue
*/
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// NSOperationQueue *queue = [NSOperationQueue mainQueue]; // 2.封装任务
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil]; // 3.将任务添加到队列中
// 只要将一个任务添加到alloc/init的队列中, 那么队列内部会自动调用start
// 只要将一个任务添加到alloc/init的队列中, 就会开启一个新的线程执行队列
[queue addOperation:op1];
[queue addOperation:op2];
- (void)addOperationWithBlock:(void (^)(void))block;
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2.封装任务
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1 = %@", [NSThread currentThread]);
}];
[op1 addExecutionBlock:^{
NSLog(@"2 = %@", [NSThread currentThread]);
}]; // 3.将任务添加到队列中
[queue addOperation:op1];
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2.将任务添加到队列中
// addOperationWithBlock方法会做两件事情
// 2.1.根据传入的block, 创建一个NSBlockOperation对象
// 2.2.将内部创建好的NSBlockOperation对象, 添加到队列中
[queue addOperationWithBlock:^{
NSLog(@"1 = %@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"2 = %@", [NSThread currentThread]);
}];
2、最大并发数
什么是并发数
同时执行的任务数
比如,同时开3个线程执行3个任务,并发数就是3
最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
// 1.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init
];
// maxConcurrentOperationCount 默认等于 -1, 代表不限制, 可以创建N多线程
// 默认就是并发
// 如果想实现串行, 那么就设置maxConcurrentOperationCount = 1
// 注意: 最大并发数, 不能设置为0, 否则任务不会被执行 \
如果想再主线程中执行任务, 那么直接创建mainQueu即可
queue.maxConcurrentOperationCount = ; // 2.创建任务
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"1 = %@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"2 = %@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:];
NSLog(@"3 = %@", [NSThread currentThread]);
}]; // 3.将任务添加到队列中
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
3、队列的取消、暂停、恢复
取消队列的所有操作
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
// 任务只要被取消, 就不会再恢复了
// 注意: 取消任务和暂停任务一样, 不会取消当前正在执行的任务, 只能取消还未执行的任务
[self.queue cancelAllOperations];
// 判断用户是否点击了取消
if (self.cancelled) {
return;
}
暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
// 暂停队列中的任务
// 如果是YES, 代表需要暂停
// 如果是NO ,代表不需要暂停 == 恢复执行
// self.queue.suspended = YES; if (self.queue.suspended) {
// 恢复
self.queue.suspended = NO;
}else
{
// 暂停
self.queue.suspended = YES;
}
// 注意:
// 1. 如果在任务执行的过程中暂停队列中的任务, 那么当前正在执行的任务并不会被暂停, 而是会暂停队列中的下一个任务
// 2. 恢复任务, 是从队列第一个没有被执行过的任务开始恢复
// self.queue.suspended = !self.queue.suspended;
四、NSOperation的其他用法
1、操作依赖
NSOperation之间可以设置依赖来保证执行顺序
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA]; // 操作B依赖于操作A
可以在不同queue的NSOperation之间创建依赖关系
注意:不能相互依赖 比如A依赖B,B依赖A
2、操作的监听
可以监听一个操作的执行完毕
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;
例如下载两张图片 然后拼接这两张图片为一张
#import "ViewController.h" @interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
// 将最大并发数设置为1 表示队列为串行
// queue.maxConcurrentOperationCount = 1; __block UIImage *image1 = nil;
__block UIImage *image2 = nil;
// 1.开启一个线程下载第一张图片
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://www.ibayue.com/images/fileup/201411/20141103150824.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
// 2.生成下载好的图片
UIImage *image = [UIImage imageWithData:data];
image1 = image;
}]; // 2.开启一个线程下载第二长图片
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://i0.letvimg.com/lc02_yunzhuanma/201503/07/00/48/170acdff2830753f89957742b0e8f5b8_25431356/thumb/2_400_225.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
// 2.生成下载好的图片
UIImage *image = [UIImage imageWithData:data];
image2 = image; }];
// 3.开启一个线程合成图片
NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
UIGraphicsBeginImageContext(CGSizeMake(, ));
[image1 drawInRect:CGRectMake(, , , )];
[image2 drawInRect:CGRectMake(, , , )];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); // 4.回到主线程更新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"回到主线程更新UI");
self.imageView.image = newImage;
}];
}]; // 监听任务是否执行完毕
op1.completionBlock = ^{
NSLog(@"第一张图片下载完毕");
};
op2.completionBlock = ^{
NSLog(@"第二张图片下载完毕");
}; // 添加依赖
// 只要添加了依赖, 那么就会等依赖的任务执行完毕, 才会执行当前任务
// 注意:
// 1.添加依赖, 不能添加循环依赖
// [op1 addDependency:op3];
// 2.NSOperation可以跨队列添加依赖
[op3 addDependency:op1];
[op3 addDependency:op2]; // 将任务添加到队列中
[queue addOperation:op1];
[queue addOperation:op2];
[queue2 addOperation:op3];
}
@end
3、自定义NSOperation
自定义NSOperation的步骤很简单
重写- (void)main方法,在里面实现想执行的任务
重写- (void)main方法的注意点
自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
iOS开发——多线程篇——NSOperation(基于GCD多线程编程),下载图片并合成新图片的更多相关文章
- iOS开发网络篇—大文件的多线程断点下载
http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时 ...
- iOS开发网络篇—大文件的多线程断点下载(转)
http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了 ...
- iOS开发拓展篇—音频处理(音乐播放器6)
iOS开发拓展篇—音频处理(音乐播放器6) 一.图片处理 说明: Aspect表示按照原来的宽高比进行缩放. Aspectfit表示按照原来的宽高比缩放,要求看到全部图片,后果是不能完全覆盖窗口,会留 ...
- iOS开发多线程篇—NSOperation简单介绍
iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...
- iOS开发多线程篇—NSOperation基本操作
iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. ...
- iOS开发网络篇—多线程断点下载
iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始, ...
- iOS开发数据库篇—FMDB简单介绍
iOS开发数据库篇—FMDB简单介绍 一.简单说明 1.什么是FMDB FMDB是iOS平台的SQLite数据库框架 FMDB以OC的方式封装了SQLite的C语言API 2.FMDB的优点 使用起来 ...
- iOS开发Swift篇(02) NSThread线程相关简单说明
iOS开发Swift篇(02) NSThread线程相关简单说明 一 说明 1)关于多线程部分的理论知识和OC实现,在之前的博文中已经写明,所以这里不再说明. 2)该文仅仅简单讲解NSThread在s ...
- 李洪强iOS开发Swift篇---12_NSThread线程相关简单说明
李洪强iOS开发Swift篇---12_NSThread线程相关简单说明 一 说明 1)关于多线程部分的理论知识和OC实现,在之前的博文中已经写明,所以这里不再说明. 2)该文仅仅简单讲解NSThre ...
随机推荐
- JS-纯js制作动态成绩表(流程控制语句+js内置对象)
流程控制for循环+if判断+Math对象+Array对象+Date对象制作成绩表 <!DOCTYPE html><html> <head> <meta ch ...
- Notepad++ 开启「切分窗口」同时检视、比对两份文件
Notepad++ 是个相当好用的免费纯文本编辑器,除了内建的功能相当多之外,也支持外挂模块的方式扩充各方面的应用.以前我都用 UltraEdit 跟 Emeditor,后来都改用免费的 Notepa ...
- HTML meta viewport属性详细说明
viewport并非只是ios上的独有属性,在android.winphone上同样也有viewport,下面为大家详细介绍下HTML meta viewport 什么是Viewport 手机浏览器是 ...
- WinForm------如何将GridControl数据导出到Excel
转载: http://www.cnblogs.com/xiaofengfeng/archive/2011/11/22/2258906.html 代码: SaveFileDialog saveFileD ...
- 使用RawSocket进行网络抓包
aw socket,即原始套接字,可以接收本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的,一共可以有3种方式创建这种socket. 中文名 原始套接字 外文名 RAW SOCKET ...
- codeforces 724B Batch Sort(暴力-列交换一次每行交换一次)
题目链接:http://codeforces.com/problemset/problem/724/B 题目大意: 给出N*M矩阵,对于该矩阵有两种操作: (保证,每行输入的数是 1-m 之间的数且不 ...
- servlet生命周期与工作原理
→ Jsp的本质是Servlet,Servlet是服务器端的小程序,运行在服务器,用于处理及响应客户端的请求. Servlet和JSP的区别: servlet是特殊的Java类,必须继承HttpS ...
- IE禁用Cookie后的session处理
IE禁用Cookie后解决方案:URL重写 购物车案例<IE禁用Cookie后> 购物界面ShowBook.servlet public void doGet(HttpServletReq ...
- vim插件ctags的安装和使用
vim插件ctags的安装和使用 2013-11-19 20:47 17064人阅读 评论(0) 收藏 举报 分类: 开发工具(3) linux编程(9) c/c++编程(11) 版权声明:本 ...
- Linux服务器管理: 系统的进程管理终止进程kill命令
在Linux中如何用kill终止进程: kill -l [root@localhost~]#kill -l 可以看到kill中有很多的 常用: -1 是重启一个进程 -9 是强制杀死进程 ...