猫猫学iOS(五十四)多线程网络之NSOperation重要知识

猫猫分享,必须精品

原创文章,欢迎转载。转载请注明:翟乃玉的博客
地址:http://blog.csdn.net/u013357243?viewmode=contents

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

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.回到主线程操作的代码
    }];
}];

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

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。