NSOperation相关
NSOperation简介
1.简单说明
NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤:
(1)先将需要执行的操作封装到一个NSOperation对象中
(2)然后将NSOperation对象添加到NSOperationQueue中
(3)系统会⾃动将NSOperationQueue中的NSOperation取出来
(4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏
2.NSOperation的子类
NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类
使用NSOperation⼦类的方式有3种:
(1)NSInvocationOperation
(2)NSBlockOperation
(3)自定义子类继承NSOperation,实现内部相应的⽅法
NSInvocationOperation子类
- (void)InvocationOperation
{
//创建操作对象,封装要执行的任务
/*
*参数1:目标对象
*参数2:要执行的方法
*参数3:执行方法要带的参数
*/
NSInvocationOperation *invocationOp = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task:) object:@"task1"];
//执行操作 说明:一旦执⾏操作,就会调用target的test方法
[invocationOp start];
}
- (void)task:(NSString*)str
{
NSLog(@"%@----%@",str,[NSThread currentThread]);
}
操作对象默认在主线程中执行,只有添加到队列中才会开启新的线程。即默认情况下,如果操作没有放到队列中queue中,都是同步执行。只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
- (void)InvocationOperation
{
/*
*参数1:目标对象
*参数2:要执行的方法
*参数3:执行方法要带的参数
*/
NSInvocationOperation *invocationOp1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task:) object:@"task1"];
NSInvocationOperation *invocationOp2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task:) object:@"task2"];
NSInvocationOperation *invocationOp3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task:) object:@"task3"];
//[invocationOp1 start];使用NSOperationQueue无需在写start,队列会自动执行start
//NSOperationQueue两种类型的队列:
//1.主队列:是一个串行队列,使用[NSOperationQueue mainQueue]获取
//2.非主队列:默认是并发队列,使用[[NSOperationQueue alloc]init]来创建
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:invocationOp1];
[queue addOperation:invocationOp2];
[queue addOperation:invocationOp3];
}
- (void)task:(NSString*)str
{
NSLog(@"%@----%@",str,[NSThread currentThread]);
}
NSBlockOperation子类
- (void)blockOperation
{
//blockOperationWithBlock创建一个BlockOperation
NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task1---%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task2---%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOp3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task3---%@",[NSThread currentThread]);
}];
//追加任务,如果追加的任务,可能会使用子线程执行
[blockOp3 addExecutionBlock:^{
NSLog(@"task4---%@",[NSThread currentThread]);
}];
[blockOp3 addExecutionBlock:^{
NSLog(@"task5---%@",[NSThread currentThread]);
}];
[blockOp3 addExecutionBlock:^{
NSLog(@"task6---%@",[NSThread currentThread]);
}];
[blockOp1 start];
[blockOp2 start];
[blockOp3 start];
}
NSBlockOperation也可以使用NSOperationQueue
- (void)blockOperationWithQueue
{
NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task1---%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task2---%@",[NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation *blockOp3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task3---%@",[NSThread currentThread]);
}];
[blockOp3 addExecutionBlock:^{
NSLog(@"task4---%@",[NSThread currentThread]);
}];
[blockOp3 addExecutionBlock:^{
NSLog(@"task5---%@",[NSThread currentThread]);
[blockOp3 addExecutionBlock:^{
NSLog(@"task6---%@",[NSThread currentThread]);
}];
[queue addOperation:blockOp1];
[queue addOperation:blockOp2];
[queue addOperation:blockOp3];
//简便方法
[queue addOperationWithBlock:^{
NSLog(@"task7---%@",[NSThread currentThread]);
}];
}
自定义Operation
自定义Operation的作用:
1.封装隐蔽大量的任务执行代码。 2.提高代码的复用
自定义的Operation只需重写NSOperation的main方法即可,大量的操作代码放入main执行就可以了
NSOperationQueue最大并发数
设定队列在同一时间最多能够执行任务的数量
queue.maxConcurrentOperationCount = 4;
如果想做到串行执行队列,只需把最大并发数设置为1即可
最大并发数大于0,就是并发队列
注意:最大并发数不能设置为0,为0不会做任何事情
最大并发数的默认值其实是-1,表示不收任何限制的意思
队列的暂停,继续,取消方法
队列里的任务是有状态的
- 已经执行完毕
- 正在执行中
- 等待执行
暂停、继续方法
//通过设置YES和NO达到暂停和继续,
//注意:无法暂停当前正在执行的任务
[queue setSuspended:[(BOOL)]]
取消
//被取消的任务是无法再恢复执行的
//注意:无法取消当前正在执行的任务
[queue cancelAllOperations];
关于自定义的Operation的取消
放在main中的所有操作都被看做是一个任务,无论代码有多长有多复杂
但可以设置cancel在操作过程中中断
- (void)main
{
for(int i = 0; i < 10000; i++)
{
NSLog(@"--download1--%d--%@",i,[NSThread currentThread]);
}
if([self cancel])return;//设置cancel,如果检测到任务被取消,则不再向下执行
for(int i = 0; i < 10000; i++)
{
NSLog(@"--download2--%d--%@",i,[NSThread currentThread]);
}
if([self cancel])return;
for(int i = 0; i < 10000; i++)
{
NSLog(@"--download3--%d--%@",i,[NSThread currentThread]);
}
}
操作依赖
如果希望一个队列中的任务按一定的顺序执行,某个任务执行完后再执行另外一个任务,就可以用操作依赖实现
- (void)blockOperationWithQueueAndDependency
{
NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task1---%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task2---%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOp3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task3---%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOp4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task4---%@",[NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//添加依赖,希望的顺序为3->2->4->1
[blockOp1 addDependency:blockOp4];
[blockOp4 addDependency:blockOp2];
[blockOp2 addDependency:blockOp3];
[queue addOperation:blockOp1];
[queue addOperation:blockOp2];
[queue addOperation:blockOp3];
[queue addOperation:blockOp4];
}
注意:操作依赖不能循环依赖,比如:
[blockOp1 addDependency:blockOp4];
[blockOp4 addDependency:blockOp1];
造成的后果是2个任务都不会被执行,但程序不会造成奔溃
操作依赖不但可以在同一个队列,也可以跨队列依赖
监听
监听一个操作是否完成,并且设置完成后做什么
blockOp1.completionBlock = ^{
NSLog(@"---blockOp1完成---");
};
NSOperation之间的通信
下载图片的案例
- (void)downloadImage
{
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://awb.img.xmtbang.com/img/uploadnew/201504/10/2dde4dcc2dc74293b6433416bcf76a03.jpg"];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
NSLog(@"download---%@",[NSThread currentThread]);
//回到主队列
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
NSLog(@"UI---%@",[NSThread currentThread]);
}];
}];
[queue addOperation:blockOp];
}