多线程之NSOperation和NSOperationQueue
这篇文章里我将不过多的谈及理论知识,这些东西会的自然会,不会的,看多了也是云里雾里。下面我讲更多的用代码+注释的方式来讲如何使用NSOperation和NSOperationQueue。
1、NSOperation。是抽象类,不能够直接使用,而是使用子类NSInvocationOperation和NSBlockOperation来实际执行任务。NSOperation本身和多线程是没有任何关系的,她只是封装了一个代码段和数据去实现一个功能。
1.1、NSInvocationOperation,基于一个对象和selector来创建操作。看下面的代码:
 - (void)invocationOperation {
     NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startOpration) object:nil];
     [operation setCompletionBlock:^{
         NSLog(@"执行完成,是否主线程:%@", [NSThread isMainThread] ==  ? @"YES" : @"NO");
     }];
     [operation start];  //启动任务
     [operation cancel]; //取消任务
     [operation isExecuting];    //任务是否在执行
     [operation isFinished];     //任务是否已经结束
 }
 - (void)startOpration {
     NSLog(@"开始执行,是否主线程:%@", [NSThread isMainThread] ==  ? @"YES" : @"NO");
 }
首先是创建了一个operation,并给operation添加了一个需要执行的方法:startOpration。其中Line4中的方法将会在operation执行完成后执行,当然不是必须的,如果需要在operation执行完进行一些操作,可以写上这个方法。
下面是执行的结果:
-- ::19.577 NSOperation[:] 开始执行,是否主线程:YES
-- ::19.577 NSOperation[:] 执行完成,是否主线程:NO
根据上面执行的结果,我们可以发现, startOpration 这个方法是在主线程执行的。至于Line4~Line6是在子线程执行的,则不在今天的讨论内容中,略过。
1.2、NSBlockOperation。相对于NSInvocationOperation,NSBlockOperation则是将selector中需要调用的方法使用Block进行了封装,使用起来更加的方便。关于Block的使用,不明白的同学可以参考我的上一篇博客。
NSBlockOperation对象能够并发的执行一个或多个Block对象,所有相关的Block都执行完成之后,操作才算完成。下面看代码:
 - (void)blockOperation {
     //创建一个操作
     NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"%d,%@,是否主线程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] ==  ? @"YES" : @"NO");
     }];
     //通过addExecutionBlock方法添加Block操作
     [blockOperation addExecutionBlock:^{
         NSLog(@"%d,%@,是否主线程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] ==  ? @"YES" : @"NO");
     }];
     [blockOperation addExecutionBlock:^{
         NSLog(@"%d,%@,是否主线程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] ==  ? @"YES" : @"NO");
     }];
     [blockOperation addExecutionBlock:^{
         NSLog(@"%d,%@,是否主线程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] ==  ? @"YES" : @"NO");
     }];
     [blockOperation addExecutionBlock:^{
         NSLog(@"%d,%@,是否主线程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] ==  ? @"YES" : @"NO");
     }];
     //执行操作
     [blockOperation start];
     //上面的几个Block是并发执行的,将会在不同的线程中执行,
 }
下面是执行的结果:
-- ::28.585 NSOperation[:] ,<NSThread: 0x7f97cad07c30>{number = , name = main},是否主线程:YES
-- ::28.585 NSOperation[:] ,<NSThread: 0x7f97cae223c0>{number = , name = (null)},是否主线程:NO
-- ::28.585 NSOperation[:] ,<NSThread: 0x7f97cac0eb60>{number = , name = (null)},是否主线程:NO
-- ::28.586 NSOperation[:] ,<NSThread: 0x7f97cad07c30>{number = , name = main},是否主线程:YES
-- ::28.585 NSOperation[:] ,<NSThread: 0x7f97cad06530>{number = , name = (null)},是否主线程:NO
可以从上面的执行结果中,很容易的发现,程序是并行的执行。而创建的操作,也就是:Line4是在主线程中执行,而其他通过通过 addExecutionBlock 方法添加的Block操作则是在不同的线程中执行。
通过上面的说明,我要总结的是:NSOperation以及子类,只是一个操作,本身无主线程和子线程的区分,可以在任意线程中使用。也就是,在主线程中创建的操作将在主线程中执行,在子线程中创建的操作将在子线程中执行。而实现多线程可以配合NSOperationQueue来实现。下面来介绍NSOperationQueue。
2.NSOperationQueue,是操作队列,它用来管理一组NSOperation对象的执行,会根据需要自动为NSOperation对象开辟适合数量的线程,以完成任务的并行执行。下面上代码:
 - (void)operationQueue {
     //创建一个任务队列,alloc(new)出来的任务队列将会在子线程中执行,并且是并发执行
     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
     //创建操作NSInvocationOperation
     for (int i = ; i < ; i++) {
         NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startOpration) object:nil];
         [queue addOperation:operation];
     }
     //创建NSBlockOperation操作
     for (int i = ; i < ; i++) {
         NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
             NSLog(@"%d,%@,%d", __LINE__, [NSThread currentThread], [NSThread isMainThread]);
         }];
         //将操作添加到队列中
         [queue addOperation:blockOperation];
     }
     //设置最大并发数,当把最大并发数设置1时,此时队列相当于串行执行。
     queue.maxConcurrentOperationCount = ;
     //添加依赖关系
     NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"这是任务1,依赖于任务2");
     }];
     NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"这是任务2");
     }];
     //添加依赖关系
     //添加依赖关系时,注意不能添加互相依赖,如A依赖B,B依赖A
     [op1 addDependency:op2];
     //添加依赖关系必须在任务添加到队列之前设置
     [queue addOperation:op1];
     [queue addOperation:op2];
     //回到主线程的操作
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
         NSLog(@"%d,%@,%d", __LINE__, [NSThread currentThread], [NSThread isMainThread]);
     }];
 }
下面是执行的结果:
-- ::11.625 NSOperation[:] 开始执行,是否主线程:NO
-- ::11.625 NSOperation[:] 开始执行,是否主线程:NO
-- ::11.625 NSOperation[:] 开始执行,是否主线程:NO
-- ::11.625 NSOperation[:] 开始执行,是否主线程:NO
-- ::11.625 NSOperation[:] 开始执行,是否主线程:NO
-- ::11.626 NSOperation[:] ,<NSThread: 0x7f852bc099f0>{number = , name = (null)},
-- ::11.627 NSOperation[:] ,<NSThread: 0x7f852bf0db10>{number = , name = (null)},
-- ::11.628 NSOperation[:] ,<NSThread: 0x7f852bc46ee0>{number = , name = (null)},
-- ::11.628 NSOperation[:] ,<NSThread: 0x7f852bc4fe00>{number = , name = (null)},
-- ::11.628 NSOperation[:] ,<NSThread: 0x7f852be0a130>{number = , name = (null)},
-- ::11.629 NSOperation[:] 这是任务2
-- ::11.629 NSOperation[:] 这是任务1,依赖于任务2
-- ::11.631 NSOperation[:] ,<NSThread: 0x7f852bd05190>{number = , name = main},
从上面的执行结果中,我们可以得到几个结论:1.首先队列中的任务都是在子线程中执行的;2.队列中的任务是并发执行的。而常用到的添加依赖关系,以及操作完成之后回到主线程的方法在上面的代码中都有体现。
需要说明的是,一旦将operation添加到队列中后,队列就拥有了这个操作,操作将不能从队列中删除,只能取消一个操作,或者取消所有的操作。取消一个操作的方法:
[operation cancel];
取消所有操作的方法:
[queue cancelAllOperations];
如果想要暂停操作的执行可以使用方法: [queue setSuspended:YES]; 来实现。但是暂停不会导致正在执行的操作被暂停,只会阻止队列调度新的操作执行。可以通过方法: [queue setSuspended:NO]; 来继续队列的执行。
3、最后做一个简单的总结。NSInvocationOperation 和 NSBlockOperation的功能是开启一个线程任务,这个线程任务处于子线程和主线程取决于线程任务是在哪个线程中开辟的。这些任务可以使用线程任务队列NSOperationQueue来管理,当new一个队列时,队列所管理的任务都在子线程中执行.当使用[NSOperationQueue mainQueue]时,队列管理的任务在主线程中执行。
以上就是这篇文章的多有内容,如果有不对或者不足的地方,请大家在评论中指出,大家一起讨论。
多线程之NSOperation和NSOperationQueue的更多相关文章
- iOS多线程之NSOperation,NSOperationQueue
		
使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...
 - iOS多线程之NSOperation和NSOperationQueue的使用
		
一:NSOperation 两个子类+重写main方法 NSInvocationOperation NSBlockOperation 有个类方法 BlockOprationWith: 还有就是自己个子 ...
 - 多线程之NSOperation
		
关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD
 - iOS多线程之NSOperation详解
		
使用NSOperation和NSOperationQueue进行多线程开发,只要将一个NSOperation(实际开发中需要使用其子类 NSInvocationOperation,NSBlockOpe ...
 - iOS-多线程之NSOperation
		
前言 这篇文章主要讲NSOperation的使用. What 使用NSOperation和NSOperationQueue进行多线程开发类似于线程池,只要将一个NSOperation(实际开发中需要使 ...
 - IOS多线程之NSOperation学习总结
		
NSOperation简介 1.NSOperation的作用 配合使用NSOperation和NSOperationQueue也能实现多线程编程 2.NSOperation和NSOperationQu ...
 - iOS 多线程之NSOperation篇举例详解
		
这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇.总篇也包含了此文的链接.本文讲解的知识点有NSBlockOperationClick,队列, ...
 - [转]  iOS多线程编程之NSOperation和NSOperationQueue的使用
		
<iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...
 - iOS多线程编程之NSOperation和NSOperationQueue的使用
		
前一篇 <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是 ...
 
随机推荐
- _set_invalid_parameter_handler异常处理函数
			
VS2005之后的版本,微软增加了一些新的异常机制,新机制在出现错误时默认不通知应用程序,这时程序就崩溃了.所以这种情况下,必须调用_set_invalid_parameter_handler._se ...
 - codeforces B. Strongly Connected City(dfs水过)
			
题意:有横向和纵向的街道,每个街道只有一个方向,垂直的街道相交会产生一个节点,这样每个节点都有两个方向, 问是否每一个节点都可以由其他的节点到达.... 思路:规律没有想到,直接爆搜!每一个节点dfs ...
 - java中getBytes方法可能使图片文件产生的问题
			
InputStream is = new FileInputStream(fl); ImageInputStream iis = ImageIO.createImageInputStream(is); ...
 - MongoDB 基础命令行
			
本文专门介绍MongoDB的命令行操作.其实,这些操作在MongoDB官网提供的Quick Reference上都有,但是英文的,为了方便,这里将其稍微整理下,方便查阅. 登录和退出 mongo命令直 ...
 - Solr搜索服务架构图
			
来源:http://www.open-open.com/lib/view/open1400576900081.html
 - Velocity魔法堂系列一:入门示例
			
一.前言 Velocity作为历史悠久的模板引擎不单单可以替代JSP作为Java Web的服务端网页模板引擎,而且可以作为普通文本的模板引擎来增强服务端程序文本处理能力.而且Velocity被移植到不 ...
 - 加密–RSA前端与后台的加密&解密
			
1. 前言 本问是根据网上很多文章的总结得到的. 2. 介绍 RSA加密算法是一种非对称加密算法. 对极大整数做因数分解的难度决定了RSA算法的可靠性.换言之,对一极大整数做因数分解愈困难,RSA算法 ...
 - 整理的有用的一些EF的CommonDAL小封装
			
CommonDAL封装: using System; using System.Collections.Generic; using System.Data.Entity; using System. ...
 - 【C++】第1章 在VS2015中用C++编写控制台应用程序
			
分类:C++.VS2015 创建日期:2016-06-12 一.简介 看到不少人至今还在用VC 6.0开发工具学习C++,其实VC 6.0开发工具早就被淘汰了.这里仅介绍学习C++时推荐使用的两种开发 ...
 - CSS代码重构
			
CSS代码重构的目的 我们写CSS代码时,不仅仅只是完成页面设计的效果,还应该让CSS代码易于管理,维护.我们对CSS代码重构主要有两个目的:1.提高代码性能2.提高代码的可维护性 提高代码性能 提高 ...