zoukankan      html  css  js  c++  java
  • AJ学IOS(54)多线程网络之NSOperation重要知识

    AJ分享,必须精品

    一:队列的类型与队列添加任务

    1: 主队列

    • [NSOperationQueue mainQueue]
    • 添加到”主队列”中的操作,都会放到主线程中执行。

    2:非主队列

    • [[NSOperationQueue alloc] init]
    • 添加到”非主队列”中的操作,都会放到子线程中执行。

    3:队列添加任务

      • (void)addOperation:(NSOperation *)op;
      • (void)addOperationWithBlock:(void (^)(void))block;

    二:常见用法

    1: 设置最大并发数

    (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3。
    (2)最大并发数:同一时间最多只能执行的任务的个数。
    (3)最⼤大并发数的相关⽅方法。
    - (NSInteger)maxConcurrentOperationCount;
    - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
    说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。
    注意:num的值并不代表线程的个数,仅仅代表线程的ID。
    提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // 1.创建一个队列(非主队列)
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        // 2.设置最大并发(最多同时并发执行2个任务)
        queue.maxConcurrentOperationCount = 2;
    
        // 3.添加操作到队列中(自动异步执行任务,并发)
        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]);
        }];
        NSInvocationOperation *operation5 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
    
        [queue addOperation:operation1];
        [queue addOperation:operation2];
        [queue addOperation:operation3];
        [queue addOperation:operation4];
        [queue addOperation:operation5];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片5---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片6---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片7---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片8---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片9---%@", [NSThread currentThread]);
        }];
    }
    

    效果:我们设置了9个模拟下载的操作,同一时间开启的线程最多为两个,注意,途中有2,3,4 三条线程,但是我们保证了再同一时间只有两条线程,2开始做事,后来不做了,就换线程3,4了。
    这里写图片描述

    2: 队列的其他操作

    • 取消所有的操作
    • (void)cancelAllOperations;
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // 1.创建一个队列(非主队列)
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //    // 2.设置最大并发(最多同时并发执行2个任务)
    //    queue.maxConcurrentOperationCount = 2;
    
        // 3.添加操作到队列中(自动异步执行任务,并发)
        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]);
        }];
        NSInvocationOperation *operation5 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
    
        [queue addOperation:operation1];
        [queue addOperation:operation2];
        [queue addOperation:operation3];
        [queue addOperation:operation4];
        [queue addOperation:operation5];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片5---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片6---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片7---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片8---%@", [NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"下载图片9---%@", [NSThread currentThread]);
        }];
    
        [queue cancelAllOperations];   
    }

    结果图:
    这里写图片描述
    这个的用法其实是在管理内存时候用的

    应该这么用

    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
    
        [queue cancelAllOperations]; // 取消队列中的所有任务(不可恢复)
    }

    • 暂停所有的操作
      [queue setSuspended:YES];

    • 恢复所有的操作
      [queue setSuspended:NO];

    跟取消所有操作差不多,实际情况中这样用,当我们的tableview跟客户交互的时候(滚动)暂停,不交互了继续执行

    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
    //    [queue setSuspended:YES]; // 暂停队列中的所有任务
    }
    
    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
    {
    //    [queue setSuspended:NO]; // 恢复队列中的所有任务
    }
    

    三:操作之间的依赖(面试题)

    • NSOperation之间可以设置依赖来保证执行顺序
    • [operationB addDependency:operationA];
      // 操作B依赖于操作A,等操作A执行完毕后,才会执行操作B
    • 注意:不能相互依赖,比如A依赖B,B依赖A
    • 可以在不同queue的NSOperation之间创建依赖关系

    简单来说就是让线程执行有顺序,是一个执行依赖于另一个线程的执行。

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        /**
         假设有A、B、C三个操作,要求:
         1. 3个操作都异步执行
         2. 操作C依赖于操作B
         3. 操作B依赖于操作A
         */
    
        // 1.创建一个队列(非主队列)
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        // 2.创建3个操作
        NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"A---%@", [NSThread currentThread]);
        }];
    
        NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"B---%@", [NSThread currentThread]);
        }];
        NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"C---%@", [NSThread currentThread]);
        }];
    
        // 设置依赖
        [operationB addDependency:operationA];
        [operationC addDependency:operationB];
    
        // 3.添加操作到队列中(自动异步执行任务)
        [queue addOperation:operationC];
        [queue addOperation:operationA];
        [queue addOperation:operationB];
    
    }
    

    效果
    这里写图片描述

    四:线程之间的通信

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        // 1.执行一些比较耗时的操作的代码
    
    
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            // 2.回到主线程操作的代码
        }];
    }];

    这个回看前面下载图片类似的案例就可以了。就是在子线程执行了然后会回主线程进行操作。

  • 相关阅读:
    174. Dungeon Game
    240. Search a 2D Matrix II
    300. Longest Increasing Subsequence
    test markdown style
    多源多汇费用流——poj2516
    费用流消圈算法(构造残量网络)
    费用流模板(带权二分图匹配)——hdu1533
    最大流模板——进阶指南整理
    最大流任务调度+离散化——hdu2883
    最大流拆点——hdu2732,poj3436
  • 原文地址:https://www.cnblogs.com/luolianxi/p/4990313.html
Copyright © 2011-2022 走看看