NSoperation 和 NSOperationQueue
- NSOperation 是个抽象类,并不具备封装操作的能力,必须使用他的子类
- 使用NSOperation子类的方式有3种
- NSInvocationOperation
- NSBlockOperation
- 自定义子类继承NSOperation,实现内部相应的方法
基本使用NSOperation
- 主队列:
- 初始化方法:[NSOperationQueue mainQueue]
- 凡是添加到主队列中的任务(NSOperation),都会放到主队列中执行
- 其他队列:
- 初始化方法:[[NSOperationQueue alloc] init]
- 同时包含了:串行、并发功能
- 添加这种队列的任务(NSOperation),就会自动放到子线程执行
最大并发操作数(MaxConcurrentOperationCount)
属性(suspend)挂起 (Cancel)取消操作
线程的使用
#第一种类型写法
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 创建操作(任务)
// 创建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];
// 创建NSBlockOperation
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download4 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download5 --- %@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download6 --- %@", [NSThread currentThread]);
}];
// 创建HBOperation(自定义)
HBOperation *op5 = [[XMGOperation alloc] init];
// 添加任务到队列中
[queue addOperation:op1];
// [op1 start] 默认已经执行了
[queue addOperation:op2];
// [op2 start]
[queue addOperation:op3];
// [op3 start]
[queue addOperation:op4];
// [op4 start]
[queue addOperation:op5];
// [op5 start]
总结: 先创建队列,然后创建操作,在将操作添加到队列中执行
#第二种类型写法
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}];
总结: 让Queue使用block进行添加操作(Operation )
# 最大并发数
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发操作数
// queue.maxConcurrentOperationCount = 2;
queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
// 添加操作
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"download2 --- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"download3 --- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"download4 --- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"download5 --- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
[queue addOperationWithBlock:^{
NSLog(@"download6 --- %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:0.01];
}];
总结:最大并发数(maxConcurrentOperationCount)默认是-1,是否开启多线程取决于最大并发数
**************************************************************************
#挂起(suspend)
@interface ViewController ()
/** 队列 */
@property (nonatomic, strong) NSOperationQueue *queue;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发操作数
queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
// 添加操作
[queue addOperationWithBlock:^{
for (NSInteger i = 0; i<5000; i++) {
NSLog(@"download1 -%zd-- %@", i, [NSThread currentThread]);
}
}];
[queue addOperationWithBlock:^{
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download2 --- %@", [NSThread currentThread]);
}
}];
[queue addOperationWithBlock:^{
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download3 --- %@", [NSThread currentThread]);
}
}];
self.queue = queue;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.queue.isSuspended) {
// 恢复队列,继续执行
self.queue.suspended = NO;
} else {
// 暂停(挂起)队列,暂停执行
self.queue.suspended = YES;
}
}
总结:当线程挂起的时候,当前线程会被停止,后面的线程不会再继续执行了,如果是当前for循环并没有结束,那么即使是挂起状态当前for循环也会执行完成,因为,for循环是不可控的。
**************************************************************************
#取消(cancelAllOperations)
[self.queue cancelAllOperations];
总结:取消队列中的所有线程
#自定义NSOperation
1. 首先得继承NSOperation(.h文件)
2.重写main方法(.m文件)
***********************.m文件**************************
/**
* 需要执行的任务
*/
- (void)main
{
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download1 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download2 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
for (NSInteger i = 0; i<1000; i++) {
NSLog(@"download3 -%zd-- %@", i, [NSThread currentThread]);
}
if (self.isCancelled) return;
}
注意:自定义的Operation需要判断是否取消了
**********************************************************
# 操作依赖
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download1----%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download2----%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3----%@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"download4----%@", [NSThread currentThread]);
}
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download5----%@", [NSThread currentThread]);
}];
op5.completionBlock = ^{
NSLog(@"op5执行完毕---%@", [NSThread currentThread]);
};
// 设置依赖
[op3 addDependency:op1];
[op3 addDependency:op2];
[op3 addDependency:op4];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue addOperation:op5];
}
总结:所谓依赖(Dependency)就是当前对象想要执行就必须让他的依赖先完成
所以op3想要先执行就必须让op1 op2 op4 先执行,也就是op3 在op1 op2 op4 执行后面
**************************************************************************
#实现进程的通信
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
__block UIImage *image1 = nil;
// 下载图片1
NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
image1 = [UIImage imageWithData:data];
}];
__block UIImage *image2 = nil;
// 下载图片2
NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
// 加载图片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成图片
image2 = [UIImage imageWithData:data];
}];
// 合成图片
NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{
// 开启新的图形上下文
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
// 绘制图片
[image1 drawInRect:CGRectMake(0, 0, 50, 100)];
image1 = nil;
[image2 drawInRect:CGRectMake(50, 0, 50, 100)];
image2 = nil;
// 取得上下文中的图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 结束上下文
UIGraphicsEndImageContext();
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
[combine addDependency:download1];
[combine addDependency:download2];
[queue addOperation:download1];
[queue addOperation:download2];
[queue addOperation:combine];
}
总结:合成图片必须有两章图片,所以得用依赖来设置顺序,下载图片,合成图片都是放在子线程中的刷新UI是返回主线程中的。