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 ...
随机推荐
- CSS3-column分栏
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- oneM2M启动Release 3标准化,华为引领物联网技术布局
http://developer.huawei.com/cn/ict/news/cn/2016/06/onem2m [韩国,首尔,2016年6月] 国际权威的物联网组织oneM2M召开第23次技术全会 ...
- nosql理解
1.NoSQL是什么? NoSQL 是 Not Only SQL 的缩写,意即"不仅仅是SQL"的意思,泛指非关系型的数据库.强调Key-Value Stores和文档数据库的优点 ...
- 9.25 DOM作业
一<style type="text/css">*{margin:0px auto; padding:0px; font-family:微软雅黑; font-size: ...
- elasticsearch scroll api--jestclient invoke
@Test public void testScroll(){ JestClientFactory factory = new JestClientFactory(); factory.setHttp ...
- 写Action的三种方法
Action类似于servlet,在用户对浏览器输入url访问的时候充当控制器的角色.它在访问时产生,执行execute()之后就销毁了. 写Action是代理事务,它实现的三种方式是: (1)POJ ...
- 从零开始HTML(一 2016/10/17)
就是准备跟着霹雳猿教程过一遍HTML啦,边看边记录更便于理解记忆吧~ 1.属性 HTML 标签可以拥有属性.属性提供了有关 HTML 元素的更多的信息.属性总是以名称/值对的形式出现,比如:name= ...
- String类中的一些函数使用方法
最常用的就是Length()函数了,求字符串的长度 String s="";int i=s.length();i结果为0. 如果是String s=null;int i=s.len ...
- VS编译器从DLL导出模板类
DLL与模板 http://msdn.microsoft.com/en-us/library/twa2aw10.aspx http://www.codesynthesis.com/~boris/blo ...
- 彻底解决Ubuntu 14.04 重启后DNS配置丢失的问题
最近得到一个比较好用的DNS,每次重启后都修改DNS配置文件 /etc/resolv.conf 重启就会失效 从网上得知 /etc/resolv.conf中的DNS配置是从/etc/resolvcon ...