美文网首页程序员iOS Developer我的ios进阶
iOS多线程-多线程实现之NSOperation

iOS多线程-多线程实现之NSOperation

作者: deve_雨轩 | 来源:发表于2016-02-09 12:18 被阅读2774次
    • NSOperation的作用

      • 配合使用NSOperation和NSOperationQueue也能实现多线程编程
    • 具体实现步骤

      • 先将需要执行的操作封装到一个NSOperation对象中
      • 然后将NSOperation对象添加到NSOperationQueue中
      • 系统会自动将NSOperationQueue中的NSOperation取出来
      • 将取出的NSOperation封装的操作放到一条新线程中执行
    • NSOperation是一个抽象类,并不具备封装操作的能力,必须使用其子类

    • 使用NSOperation子类的方式有三种

      • NSInvocationOperation
      • NSBlockOperation
      • 自定义子类继承NSOperation,实现内部响应的方法

    废话不多说上代码

    • NSInvocationOperation单独使用
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //创建InvocationOperation 对象
        //注意: 如果没有放入队列中的话需要手动启动
        //
        /*
         第一个参数: 目标对象
         第二个参数: 调用目标对象的那个方法
         第三个参数: 目标方法需要传入的参数, 如果没有参数写nil
         */
        NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
    
        //启动任务
        //默认情况下(在没有被放入队列中时),调用start方法,是在当前线程下执行任务,等任务执行完毕才会继续往下执行(会阻塞当前线程).
        //start 底层其实就是去调用 main 方法 [operation main]
        [operation start];
    }
    
    • NSInvocationOperation配合NSOperationQueue使用
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //创建NSOperationQueue对象
        //直接alloc/init手动创建的NSOperationQueue对象,是在子线程中执行,默认并发执行
        //[NSOperationQueue mainQueue]创建出来的NSOperationQueue对象,是在主线程中执行
        NSOperationQueue * queue = [[NSOperationQueue alloc] init];
    
        NSInvocationOperation * invocation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
        NSInvocationOperation * invocation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
    
        //添加到队列后,就不需要再手动start了
        //异步执行
            //注意:如果是主队列,并且当前线程正好也是主线程的话,会先执行完所有代码,然后再去执行队列中的任务
        [queue addOperation:invocation1];
        [queue addOperation:invocation2];
    }
    
    • NSBlockOperation单独使用
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //创建BlockOperation对象
        //注意: 如果没有放入队列中的话需要手动启动
        NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"1==%@",[NSThread currentThread]);
        }];
    
        //通过addExecutionBlock方法动态添加多个任务
        [operation addExecutionBlock:^{
    
            NSLog(@"2==%@",[NSThread currentThread]);
        }];
    
        [operation addExecutionBlock:^{
    
            NSLog(@"3==%@",[NSThread currentThread]);
        }];
    
        [operation addExecutionBlock:^{
    
            NSLog(@"4==%@",[NSThread currentThread]);
        }];
        //启动任务
        //默认情况下(在没有被放入队列中时),调用start方法,会等所有任务执行完毕才会继续执行下去,也就是说会阻塞当前线程
        //最先添加的任务是在当前线程中执行, 后添加的任务是在子线程中执行
        //start 底层其实就是去调用 main 方法 [operation main]
        [operation start];
    
        NSLog(@"end");
    }
    
    • NSBlockOperation配合NSOperationQueue使用
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //创建NSOperationQueue对象
        //直接alloc/init手动创建的NSOperationQueue对象,是在子线程中执行,默认并发执行
        //[NSOperationQueue mainQueue]创建出来的NSOperationQueue对象,是在主线程中执行
        NSOperationQueue * queue = [[NSOperationQueue alloc] init];
    
        NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"%@",[NSThread currentThread]);
        }];
    
        //添加到队列后,就不需要再手动start了
        //异步执行
        //注意:如果是主队列,并且当前线程正好也是主线程的话,会先执行完所有代码,然后再去执行队列中的任务
        [queue addOperation:operation];
    
        //直接通过queue的addOperationWithBlock方法来添加任务
        [queue addOperationWithBlock:^{
            NSLog(@"%@",[NSThread currentThread]);
        }];
    }
    
    • 自定义子类继承NSOperation,实现内部响应的方法

      • 前面说过执行任务的底层实现其实就是调用NSOperation对象的main方法.
      • 所有我们只要自定一个类继承NSOperation,重写main,把任务代码编写在面方法中即可.系统自带的NSInvocationOperation和NSBlockOperation的怎么用,自定义的NSOperation也就怎么用.
    #import <Foundation/Foundation.h>
    
    @interface YXOperation : NSOperation
    @end
    
    @implementation YXOperation
    -(void)main{
        NSLog(@"%@",[NSThread currentThread]);
        NSLog(@"耗时操作代码........");
    }
    @end
    
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
     // 创建自定义的NSOperation对象
        YXOperation * operation1 = [[YXOperation alloc] init];
        YXOperation * operation2 = [[YXOperation alloc] init];
        YXOperation * operation3 = [[YXOperation alloc] init];
        YXOperation * operation4 = [[YXOperation alloc] init];
    
        //把Operation对象封装到数组中
        NSArray * operationArray = @[operation1,operation2,operation3,operation4];
    
        NSOperationQueue * queue = [[NSOperationQueue alloc] init];
    
        //把NSOperation对象数组添加到队列中
        /*
         第一个参数: NSOperation 对象数组
         第二个参数: 是否等待所有任务执行完毕,  YES(等待,会阻塞当前线程) NO(不等待)
         */
        [queue addOperations:operationArray waitUntilFinished: NO];
    
        NSLog(@"end");
    }
    
    • 队列的暂停,恢复,取消,最大并发数

    //按钮点击事件
    - (IBAction)btnClick:(id)sender {
        //设置与队列当前状态相反的值
        //执行状态就暂停,暂停状态就恢复
        //暂停之后,会把当前正在执行的任务执行完,然后不再执行任务
        //恢复之后,会接着继续执行没有执行的任务
        self.queue.suspended = !self.queue.suspended;
    
        //取消队列中所有的任务
        //注意: 取消之后就不能再恢复了,当前正在执行的任务不会被取消,
        //底层其实就是调用队列中所有NSOperation任务对象的cancel方法,可以通过队列的operations属性获取队列中所有NSOperations对象(self.queue.operations)
        //开发中,自定义Operation的时候在重写main方式,做耗时操作时,在适当的位置判断用户是否取消了任务,如果取消了直接return任务
        //self.queue cancelAllOperations];
    
    }
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        self.queue = [[NSOperationQueue alloc] init];
    
        //最大并发数:最大同时执行的任务数
        // 1.默认是-1没有限制,由系统自己决定
        // 2.不要设置为0,设置为0就不会执行任务了
        // 3.设置为1,就可以达到串行的效果
        self.queue.maxConcurrentOperationCount = 1;
    
        [self.queue addOperationWithBlock:^{
            NSLog(@"==============================================");
            for(int i = 0 ; i < 10000; i++){
                NSLog(@"%d*****%@", i ,[NSThread currentThread]);
            }
    
        }];
    
        [self.queue addOperationWithBlock:^{
            NSLog(@"==============================================");
            for(int i = 0 ; i < 10000; i++){
                NSLog(@"%d*****%@", i ,[NSThread currentThread]);
            }
    
        }];
    
        [self.queue addOperationWithBlock:^{
            NSLog(@"==============================================");
            for(int i = 0 ; i < 10000; i++){
                NSLog(@"%d*****%@", i ,[NSThread currentThread]);
            }
    
        }];
    
        [self.queue addOperationWithBlock:^{
            NSLog(@"==============================================");
            for(int i = 0 ; i < 10000; i++){
                NSLog(@"%d*****%@", i ,[NSThread currentThread]);
            }
    
        }];
    
    }
    
    • NSOperation的依赖和监听

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //创建队列
        NSOperationQueue * queue1 = [[NSOperationQueue alloc] init];
        NSOperationQueue * queue2 = [[NSOperationQueue alloc] init];
    
        //创建任务
        NSBlockOperation * operation1 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"1==%@",[NSThread currentThread]);
        }];
        NSBlockOperation * operation2 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"2==%@",[NSThread currentThread]);
        }];
        NSBlockOperation * operation3 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"3==%@",[NSThread currentThread]);
        }];
        NSBlockOperation * operation4 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"4==%@",[NSThread currentThread]);
        }];
    
        //添加依赖,并需要添加到队列之前添加依赖
        //依赖了谁,就会在谁执行完之后再执行
        //可以跨队列: 依赖对象和被依赖对象可以不再一个队列
        [operation4 addDependency:operation1];
        [operation4 addDependency:operation2];
        [operation4 addDependency:operation3];
    
        //添加监听
        //任务执行完之后,就会调用这个block,在子线程中执行
        [operation4  setCompletionBlock:^{
            NSLog(@"operation4执行完毕. %@",[NSThread currentThread]);
        }];
    
        //把任务添加到队列中
        [queue1 addOperation:operation1];
        [queue1 addOperation:operation2];
    
        [queue2 addOperation:operation3];
        [queue2 addOperation:operation4];
    }
    
    • 线程间的通信

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        NSOperationQueue * queue = [[NSOperationQueue alloc] init];
    
        [queue addOperationWithBlock:^{
           //耗时操作
    
            //回到主线程刷新UI
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                //刷新UI
            }];
        }];
    
    }
    

    相关文章

      网友评论

        本文标题:iOS多线程-多线程实现之NSOperation

        本文链接:https://www.haomeiwen.com/subject/cckykttx.html