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];
}

results matching ""

    No results matching ""