-
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];
}
-(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]);
}
}];
}
-(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
}];
}];
}