iOS多线程学习之NSOperation(一)
2015-09-05 23:39
411 查看
什么是NSOperation呢?有什么用呢?和GCD相比有什么不同呢?或者优势呢?
NSOperation底层实现是基于GCD的,比GCD多了一些简单使用的功能,使用更加面向对象
作用:配合使用NSOperation 和 NSOperationQueue也能实现多线程
NSOperation 和 NSOperationQueue实现多线程的步骤:
(1)将需要的任务先封装到一个NSOperation对象中(GCD封装在block中)
(2)然后将NSOperation添加到NSOperationQueue对象中(GCD将block添加到队列中)
(3)系统自动将NSOperationQueue中的NSOperation取出来
(4)将取出的NSOperation封装的操作放到一条新线程中执行
在使用之前还要说下:NSOperation是一个抽象类,所谓抽象类就是没什么功能的类,并不具备封装操作的能力,抽象么,具体不出来,能有啥用,只能靠想象了,但这是实际操作写代码啊,不是想想啊,所以我们就要用到它的子类了,换句话说,他的子类不抽象,可以实现封装操作
使用NSOperation子类的三种方式:
(一)NSInvocationOperation
(二)NSBlockOperation
(三)自定义子类继承NSOperation,实现内部相应的方法
下面意义列举
(一)NSInvocationOperation(这个功能基本很少用,为什么呢,下面看看就知道了)
通过打印发现,这个操作在主线程中运行的,也就是调用start方法没有开辟线程,直接变成同步(在当前线程)执行了,写了这么一大堆,然并卵,还不如直接调用[self downLoad]呢,那么下面我们想另开线程应该怎么做呢?犹如上面的步骤说明,把任务添加到NSOperationQueue对象中:
通过打印发现不是num!=1,不是主线程,添加到队列中,会自动异步执行
即使这样也感觉比较垃圾,还不如直接用NSThread呢,下面看看另一种方法
通过上面可以知道调用start是同步执行,打印出来的结果是num=1,在主线程,但是也有一点不同,在添加几个任务,再看看打印结果
打印结果多了两个线程,由此可以得知,当通过start执行任务数大于1时会开启异步线程,但是1还是在主线程,这个也很少用,另外就是面试业主要问队列,下面我们就用队列:
通过打印结果就可以知道我们将任务放到队列中后就会异步执行了,也可以这样写:
(三)NSOperationQueue
解释:先把block里面的操作包装成operation对象,在把这个对象添加到队列中,block中的任务就是在异步线程中执行,其实这样写还是有点麻烦,我们可以通过queue一步写到位:
通过打印我们就发现三个线程,说白点,就是有三个operation对象,只不过最后一个block内部帮我们封装了,而前两个是我们自己创建的
所以我们搞个任务想异步执行,可以直接用最后一个方式了。
上面是基本用法:
添加操作到队列中有两种方法:
那么高级一点的用法又长啥样啊?怎么用?先看一下下面执行的结果
打印发现,我靠,多少个任务多少条线程啊,假如我们几百个任务开了几百条线程,不用我说,你也知道占用内存太多了,太浪费资源了,而GCD内部会帮我们自动管理线程条数,最多也就4、5条,但是这是系统决定的,我们操作不了,那么我们NSOperationQueue可不可以控制线程个数来提高性能呢?答案是可以,下面我们可以设置一下最大并发数:
通过打印结果我们可以看到上面任务仅在两条线程中执行(是指同一时间开的执行任务的线程数)
NSOperation底层实现是基于GCD的,比GCD多了一些简单使用的功能,使用更加面向对象
作用:配合使用NSOperation 和 NSOperationQueue也能实现多线程
NSOperation 和 NSOperationQueue实现多线程的步骤:
(1)将需要的任务先封装到一个NSOperation对象中(GCD封装在block中)
(2)然后将NSOperation添加到NSOperationQueue对象中(GCD将block添加到队列中)
(3)系统自动将NSOperationQueue中的NSOperation取出来
(4)将取出的NSOperation封装的操作放到一条新线程中执行
在使用之前还要说下:NSOperation是一个抽象类,所谓抽象类就是没什么功能的类,并不具备封装操作的能力,抽象么,具体不出来,能有啥用,只能靠想象了,但这是实际操作写代码啊,不是想想啊,所以我们就要用到它的子类了,换句话说,他的子类不抽象,可以实现封装操作
使用NSOperation子类的三种方式:
(一)NSInvocationOperation
(二)NSBlockOperation
(三)自定义子类继承NSOperation,实现内部相应的方法
下面意义列举
(一)NSInvocationOperation(这个功能基本很少用,为什么呢,下面看看就知道了)
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self invocationQueue]; } - (void)invocationQueue { NSInvocationOperation * invoQueue = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; [invoQueue start]; } - (void)download { NSLog(@"load----%@",[NSThread currentThread]); } @end
通过打印发现,这个操作在主线程中运行的,也就是调用start方法没有开辟线程,直接变成同步(在当前线程)执行了,写了这么一大堆,然并卵,还不如直接调用[self downLoad]呢,那么下面我们想另开线程应该怎么做呢?犹如上面的步骤说明,把任务添加到NSOperationQueue对象中:
- (void)invocationQueue { NSOperationQueue * queue = [[NSOperationQueue alloc] init]; NSInvocationOperation * invoQueue = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; //[invoQueue start]; [queue addOperation:invoQueue]; } - (void)download { NSLog(@"load----%@",[NSThread currentThread]); } @end
通过打印发现不是num!=1,不是主线程,添加到队列中,会自动异步执行
即使这样也感觉比较垃圾,还不如直接用NSThread呢,下面看看另一种方法
- (void)viewDidLoad { [super viewDidLoad]; //[self invocationQueue]; [self blockQueue]; } - (void)blockQueue { NSBlockOperation * bkOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage1---%@", [NSThread currentThread]); }]; [bkOperation start]; }
通过上面可以知道调用start是同步执行,打印出来的结果是num=1,在主线程,但是也有一点不同,在添加几个任务,再看看打印结果
- (void)viewDidLoad { [super viewDidLoad]; //[self invocationQueue]; [self blockQueue]; } - (void)blockQueue { NSBlockOperation * bkOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage1---%@", [NSThread currentThread]); }]; [bkOperation addExecutionBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; [bkOperation addExecutionBlock:^{ NSLog(@"loadImage3---%@", [NSThread currentThread]); }]; [bkOperation start]; }
打印结果多了两个线程,由此可以得知,当通过start执行任务数大于1时会开启异步线程,但是1还是在主线程,这个也很少用,另外就是面试业主要问队列,下面我们就用队列:
- (void)blockQueue { NSOperationQueue * queue = [[NSOperationQueue alloc] init]; NSBlockOperation * bkOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage1---%@", [NSThread currentThread]); }]; [bkOperation addExecutionBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; [bkOperation addExecutionBlock:^{ NSLog(@"loadImage3---%@", [NSThread currentThread]); }]; [queue addOperation:bkOperation]; //[bkOperation start]; }
通过打印结果就可以知道我们将任务放到队列中后就会异步执行了,也可以这样写:
- (void)blockQueue { NSBlockOperation * bkOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage11---%@", [NSThread currentThread]); }]; [bkOperation addExecutionBlock:^{ NSLog(@"loadImage12---%@", [NSThread currentThread]); }]; NSBlockOperation * bkOperation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * bkOperation3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage3---%@", [NSThread currentThread]); }]; NSBlockOperation * bkOperation4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage4---%@", [NSThread currentThread]); }]; NSBlockOperation * bkOperation5 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage4---%@", [NSThread currentThread]); }]; NSOperationQueue * queue = [[NSOperationQueue alloc] init]; [queue addOperation:bkOperation]; [queue addOperation:bkOperation1]; [queue addOperation:bkOperation3]; [queue addOperation:bkOperation4]; [queue addOperation:bkOperation5]; //[bkOperation start]; }
(三)NSOperationQueue
- (void)viewDidLoad { [super viewDidLoad]; //[self invocationQueue]; // [self blockQueue]; [self opeationQueue]; } - (void)opeationQueue { //创建一个队列(非主队列) NSOperationQueue * queue = [[NSOperationQueue alloc] init]; //添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似) NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; [queue addOperation:blockQueue1]; [queue addOperation:blockQueue2]; }
解释:先把block里面的操作包装成operation对象,在把这个对象添加到队列中,block中的任务就是在异步线程中执行,其实这样写还是有点麻烦,我们可以通过queue一步写到位:
- (void)opeationQueue { //创建一个队列(非主队列) NSOperationQueue * queue = [[NSOperationQueue alloc] init]; //添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似) NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage1---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; [queue addOperation:blockQueue1]; [queue addOperation:blockQueue2]; [queue addOperationWithBlock:^{ NSLog(@"loadImage3---%@", [NSThread currentThread]); }]; }
通过打印我们就发现三个线程,说白点,就是有三个operation对象,只不过最后一个block内部帮我们封装了,而前两个是我们自己创建的
所以我们搞个任务想异步执行,可以直接用最后一个方式了。
- (void)viewDidLoad { [super viewDidLoad]; //[self invocationQueue]; // [self blockQueue]; [self opeationQueue]; } - (void)opeationQueue { //创建一个队列(非主队列) NSOperationQueue * queue = [[NSOperationQueue alloc] init]; //添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似) // NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{ // NSLog(@"loadImage1---%@", [NSThread currentThread]); // }]; // NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{ // NSLog(@"loadImage2---%@", [NSThread currentThread]); // }]; // [queue addOperation:blockQueue1]; // [queue addOperation:blockQueue2]; [queue addOperationWithBlock:^{ NSLog(@"loadImage3---%@", [NSThread currentThread]); }]; }
上面是基本用法:
添加操作到队列中有两种方法:
- (void)addOperation:(NSOperation *)op; - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);(点进NSOperationQueue官方文档也可以看到这两个方法)
那么高级一点的用法又长啥样啊?怎么用?先看一下下面执行的结果
- (void)opeationQueue { //创建一个队列(非主队列) NSOperationQueue * queue = [[NSOperationQueue alloc] init]; //添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似) NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage1---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue5 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; [queue addOperation:blockQueue1]; [queue addOperation:blockQueue2]; [queue addOperation:blockQueue3]; [queue addOperation:blockQueue4]; [queue addOperation:blockQueue5]; }
打印发现,我靠,多少个任务多少条线程啊,假如我们几百个任务开了几百条线程,不用我说,你也知道占用内存太多了,太浪费资源了,而GCD内部会帮我们自动管理线程条数,最多也就4、5条,但是这是系统决定的,我们操作不了,那么我们NSOperationQueue可不可以控制线程个数来提高性能呢?答案是可以,下面我们可以设置一下最大并发数:
- (void)opeationQueue { //1.创建一个队列(非主队列) NSOperationQueue * queue = [[NSOperationQueue alloc] init]; //2.设置最大并发数 queue.maxConcurrentOperationCount = 2; //3.添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似) NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage1---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; NSBlockOperation * blockQueue5 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"loadImage2---%@", [NSThread currentThread]); }]; [queue addOperation:blockQueue1]; [queue addOperation:blockQueue2]; [queue addOperation:blockQueue3]; [queue addOperation:blockQueue4]; [queue addOperation:blockQueue5]; }
通过打印结果我们可以看到上面任务仅在两条线程中执行(是指同一时间开的执行任务的线程数)
相关文章推荐
- iOS-本地推送和远程推送,常用的三方推送和常用的测试方法,推送实现和原理详解
- 快速掌握iOS开发 - 多线程开发技巧
- 苹果开发 笔记(71)CoreData
- 快速实现单例的工具类
- HDU 1017 A Mathematical Curiosity(水~)
- iOS 中内存管理备忘
- iOS开发 调整系统音量
- iOS多线程GCD
- IOS工作笔记1年,收集整理,常用方法
- IOS 类方法与实例方法的区别
- IOS 常用快捷键----蓝懿教育
- iOS8-获取当前时间的年、月、日、时、分、秒
- ios学习笔记(1)
- 苹果开发者账号那些事儿(一)
- iOS开发之XCode快捷键
- 内存管理
- iOS-QQ好友列表 iOS 页面间几种传值方式(属性,代理,block,单例,通知)
- IOS-注意事项
- iOS学习之单例
- ios状态栏隐藏设置