iOS 多线程(三)NSOperation

来源:互联网 发布:美呼软件靠谱吗 编辑:程序博客网 时间:2024/05/21 07:13

NSOperation多线程任务类,是个“抽象类”,并不具备封装操作的能力,必须使用它的子类。

使用NSOperation子类的三种方法:

  1. NSInvocationOperation
  2. NSBlockOperation
  3. 自定义子类继承NSOperation,实现内部相应方法。

1 NSInVocationOperation

- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

执行start方法,就会调用target的sel方法。
-(void)invocationOperation{    //创建NSInvocationOperation对象    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationRun) object:nil];    //开始执行    [invocationOperation start];}-(void)invocationRun{    NSLog(@"invocationRun------%@",[NSThread currentThread]);}
打印:
2016-10-11 19:19:43.281 NSOperation基本使用[576:407434] invoRun------<NSThread: 0x166454c0>{number = 1, name = main}
由此打印可知其是在主线程中运行的。
默认情况下,调用start方法并不会开启一条新线程去执行操作,而是在当前线程同步执行
需要将NSInvocationOperation放到一个NSOperationQueue中,才会异步执行

2 NSBlockOperation

+ (id)blockOperationWithBlock:(void (^)(void))block;

一执行start方法,就会执行block中的代码。
//NSBlockOperation-(void)blockOperation{    //创建NSBlockOperation对象    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOperation 1------%@",[NSThread currentThread]);    }];    //开始执行    [blockOperation start];}
打印:
2016-10-11 19:32:37.946 NSOperation基本使用[579:416891] blockOperation 1------<NSThread: 0x17632dd0>{number = 1, name = main}
由此可以看出其也是同步执行,并没有开启新线程。
添加多个任务
//NSBlockOperation-(void)blockOperation{    //创建NSBlockOperation对象    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blockOperation 1------%@",[NSThread currentThread]);    }];    // 添加额外的任务    [blockOperation addExecutionBlock:^{        NSLog(@"blockOperation 2------%@", [NSThread currentThread]);    }];    [blockOperation addExecutionBlock:^{        NSLog(@"blockOperation 3------%@", [NSThread currentThread]);    }];    [blockOperation addExecutionBlock:^{        NSLog(@"blockOperation 4------%@", [NSThread currentThread]);    }];    //开始执行    [blockOperation start];}
打印多种情况
1:
2016-10-11 19:37:44.429 NSOperation基本使用[582:417738] blockOperation 1------<NSThread: 0x15d767b0>{number = 1, name = main}2016-10-11 19:37:44.432 NSOperation基本使用[582:417738] blockOperation 3------<NSThread: 0x15d767b0>{number = 1, name = main}2016-10-11 19:37:44.432 NSOperation基本使用[582:417738] blockOperation 4------<NSThread: 0x15d767b0>{number = 1, name = main}2016-10-11 19:37:44.429 NSOperation基本使用[582:417815] blockOperation 2------<NSThread: 0x15d7a6b0>{number = 4, name = (null)}
2 :
2016-10-11 19:38:31.864 NSOperation基本使用[584:418141] blockOperation 2------<NSThread: 0x166732d0>{number = 3, name = (null)}2016-10-11 19:38:31.865 NSOperation基本使用[584:418127] blockOperation 1------<NSThread: 0x1663f980>{number = 1, name = main}2016-10-11 19:38:31.866 NSOperation基本使用[584:418141] blockOperation 3------<NSThread: 0x166732d0>{number = 3, name = (null)}2016-10-11 19:38:31.867 NSOperation基本使用[584:418127] blockOperation 4------<NSThread: 0x1663f980>{number = 1, name = main}
2016-10-11 19:39:29.995 NSOperation基本使用[586:418505] blockOperation 1------<NSThread: 0x16d10730>{number = 1, name = main}2016-10-11 19:39:29.996 NSOperation基本使用[586:418525] blockOperation 2------<NSThread: 0x16e16c70>{number = 3, name = (null)}2016-10-11 19:39:29.998 NSOperation基本使用[586:418505] blockOperation 3------<NSThread: 0x16d10730>{number = 1, name = main}2016-10-11 19:39:29.998 NSOperation基本使用[586:418525] blockOperation 4------<NSThread: 0x16e16c70>{number = 3, name = (null)}
由上面三种打印可知,NSBlockOperation封装的操作数> 1,任务执行线程不确定(不一定是开启新线程,也不一定是同步执行,像是随机的)。

3 自定义NSOperation子类

创建类继承NSOperation,实现main方法。
ZPYOperation.h
#import <Foundation/Foundation.h>@interface ZPYOperation : NSOperation@end
ZPYOperation.m
@implementation ZPYOperation-(void)main{    NSLog(@"zpyoperation main---%@",[NSThread currentThread]);}@end
使用方法
ZPYOperation *zpy = [[ZPYOperation alloc] init];[queue addOperation:zpy];

4 NSOperationQueue

NSOperation通过添加到NSOperationQueue,则会异步执行任务。
添加方式:
  1. - (void)addOperation:(NSOperation *)op;
  2. - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
  3. - (void)addOperationWithBlock:(void (^)(void))block;

第一种方式
// - (void)addOperation:(NSOperation *)op;-(void)operationQueue1{    //创建队列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    NSLog(@"默认 maxcurrent:%d",[queue maxConcurrentOperationCount]);//默认为-1    //创建操作    NSInvocationOperation *inOp1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run1) object:nil];    NSInvocationOperation *inOp2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run2) object:nil];        NSBlockOperation *blOp1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blOp1------1----%@",[NSThread currentThread]);    }];    NSBlockOperation *blOp2 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"blOp2------1----%@",[NSThread currentThread]);    }];    [blOp2 addExecutionBlock:^{        NSLog(@"blOp2------2----%@",[NSThread currentThread]);    }];    [blOp2 addExecutionBlock:^{        NSLog(@"blOp2------3----%@",[NSThread currentThread]);    }];    //添加任务到队列中    [queue addOperation:inOp1];    [queue addOperation:inOp2];    [queue addOperation:blOp1];    [queue addOperation:blOp2];}-(void)run1{    NSLog(@"run1----------%@",[NSThread currentThread]);}-(void)run2{    NSLog(@"run2----------%@",[NSThread currentThread]);}
打印:
2016-10-11 20:01:42.851 NSOperation基本使用[596:422242] 默认 maxcurrent:-12016-10-11 20:01:42.857 NSOperation基本使用[596:422312] run2----------<NSThread: 0x15d51d30>{number = 4, name = (null)}2016-10-11 20:01:42.858 NSOperation基本使用[596:422312] blOp1------1----<NSThread: 0x15d51d30>{number = 4, name = (null)}2016-10-11 20:01:42.858 NSOperation基本使用[596:422312] blOp2------1----<NSThread: 0x15d51d30>{number = 4, name = (null)}2016-10-11 20:01:42.858 NSOperation基本使用[596:422312] blOp2------2----<NSThread: 0x15d51d30>{number = 4, name = (null)}2016-10-11 20:01:42.858 NSOperation基本使用[596:422306] run1----------<NSThread: 0x15d7d720>{number = 3, name = (null)}2016-10-11 20:01:42.858 NSOperation基本使用[596:422312] blOp2------3----<NSThread: 0x15d51d30>{number = 4, name = (null)}
第二种方式,就是先将多个NSOperation对象存到一个NSArray中然后在添加到queue中而已。
第三种方式
// - (void)addOperationWithBlock:(void (^)(void))block- (void)operationQueue2{    // 创建队列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    // 添加操作到队列中    [queue addOperationWithBlock:^{        NSLog(@"addoperationWithBlock 1 --- %@", [NSThread currentThread]);    }];    [queue addOperationWithBlock:^{        NSLog(@"addoperationWithBlock 2 --- %@", [NSThread currentThread]);    }];}
打印:
2016-10-11 19:18:29.682 NSOperation基本使用[606:425449] addoperationWithBlock 2 --- <NSThread: 0x175944a0>{number = 4, name = (null)}2016-10-11 19:18:29.681 NSOperation基本使用[606:425446] addoperationWithBlock 1 --- <NSThread: 0x176a9800>{number = 3, name = (null)}

5 maxConcurrentOperationCount

最大并发数
并发数:同时执行的任务数。比如,同时开3个线程执行3个任务,并发数就是3。
- (void)operationQueue3{    // 创建队列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    // 设置最大并发操作数    //    queue.maxConcurrentOperationCount = 2;    queue.maxConcurrentOperationCount = 1; // 就变成了串行队列    // 添加操作    [queue addOperationWithBlock:^{        NSLog(@"download1 --- %@", [NSThread currentThread]);        [NSThread sleepForTimeInterval:0.01];    }];    [queue addOperationWithBlock:^{        NSLog(@"download2 --- %@", [NSThread currentThread]);        [NSThread sleepForTimeInterval:0.01];    }];    [queue addOperationWithBlock:^{        NSLog(@"download3 --- %@", [NSThread currentThread]);        [NSThread sleepForTimeInterval:0.01];    }];    [queue addOperationWithBlock:^{        NSLog(@"download4 --- %@", [NSThread currentThread]);        [NSThread sleepForTimeInterval:0.01];    }];    [queue addOperationWithBlock:^{        NSLog(@"download5 --- %@", [NSThread currentThread]);        [NSThread sleepForTimeInterval:0.01];    }];    [queue addOperationWithBlock:^{        NSLog(@"download6 --- %@", [NSThread currentThread]);        [NSThread sleepForTimeInterval:0.01];    }];}
打印:
2016-10-11 19:52:38.283 NSOperation基本使用[609:429908] download1 --- <NSThread: 0x1452fc20>{number = 3, name = (null)}2016-10-11 19:52:38.298 NSOperation基本使用[609:429908] download2 --- <NSThread: 0x1452fc20>{number = 3, name = (null)}2016-10-11 19:52:38.312 NSOperation基本使用[609:429905] download3 --- <NSThread: 0x146225e0>{number = 4, name = (null)}2016-10-11 19:52:38.326 NSOperation基本使用[609:429905] download4 --- <NSThread: 0x146225e0>{number = 4, name = (null)}2016-10-11 19:52:38.340 NSOperation基本使用[609:429905] download5 --- <NSThread: 0x146225e0>{number = 4, name = (null)}2016-10-11 19:52:38.353 NSOperation基本使用[609:429905] download6 --- <NSThread: 0x146225e0>{number = 4, name = (null)}
当设置

queue.maxConcurrentOperationCount=2;

输出如下:
2016-10-11 17:08:20.085 NSOperation基本使用[613:432467] download2 --- <NSThread: 0x15d5c0b0>{number = 6, name = (null)}2016-10-11 17:08:20.084 NSOperation基本使用[613:432416] download1 --- <NSThread: 0x15e5d990>{number = 5, name = (null)}2016-10-11 17:08:20.098 NSOperation基本使用[613:432402] download3 --- <NSThread: 0x15d759b0>{number = 4, name = (null)}2016-10-11 17:08:20.100 NSOperation基本使用[613:432416] download4 --- <NSThread: 0x15e5d990>{number = 5, name = (null)}2016-10-11 17:08:20.109 NSOperation基本使用[613:432402] download5 --- <NSThread: 0x15d759b0>{number = 4, name = (null)}2016-10-11 17:08:20.113 NSOperation基本使用[613:432416] download6 --- <NSThread: 0x15e5d990>{number = 5, name = (null)}
由此可见,当设置为1时,也就变成了串行执行,按先后顺序执行。

6 其他常用方法:

//queue管理的所有NSOperation@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;//queue管理的NSOperation数量@property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);@property NSInteger maxConcurrentOperationCount;//用来暂停和恢复队列@property (getter=isSuspended) BOOL suspended;//队列名@property (nullable, copy) NSString *name NS_AVAILABLE(10_6, 4_0);//取消所有的NSOperation- (void)cancelAllOperations;- (void)waitUntilAllOperationsAreFinished;

监听操作执行完毕及添加依赖
通过设置completionBlock属性来监听操作执行完毕。

NSOperation之间可以设置依赖来保证执行顺序,
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA];//操作B依赖于操作A
可以在不同queueNSOperation之间创建依赖关系,但是不能相互依赖比如A依赖BB依赖A

-(void)dependencyOperation{    NSOperationQueue *queue = [[NSOperationQueue alloc] init];        NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"download1----%@", [NSThread  currentThread]);    }];    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"download2----%@", [NSThread  currentThread]);    }];    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"download3----%@", [NSThread  currentThread]);    }];    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{        for (NSInteger i = 0; i<10; i++) {            NSLog(@"download4----%@", [NSThread  currentThread]);        }    }];    //监听操作执行完毕    [op4 setCompletionBlock:^{        NSLog(@"op4执行完毕---%@", [NSThread currentThread]);    }];    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"download5----%@", [NSThread  currentThread]);    }];    //监听操作执行完毕    op5.completionBlock = ^{        NSLog(@"op5执行完毕---%@", [NSThread currentThread]);    };    // 设置依赖    [op3 addDependency:op1];    [op3 addDependency:op2];    [op3 addDependency:op4];        [queue addOperation:op1];    [queue addOperation:op2];    [queue addOperation:op3];    [queue addOperation:op4];    [queue addOperation:op5];}
打印:
2016-10-11 17:56:04.208 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.208 NSOperation基本使用[626:439625] download2----<NSThread: 0x17e9a830>{number = 5, name = (null)}2016-10-11 17:56:04.211 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.211 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.209 NSOperation基本使用[626:439640] download5----<NSThread: 0x17e9ab20>{number = 7, name = (null)}2016-10-11 17:56:04.211 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.211 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.211 NSOperation基本使用[626:439640] op5执行完毕---<NSThread: 0x17e9ab20>{number = 7, name = (null)}2016-10-11 17:56:04.212 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.207 NSOperation基本使用[626:439626] download1----<NSThread: 0x17da6a60>{number = 4, name = (null)}2016-10-11 17:56:04.212 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.213 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.213 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.213 NSOperation基本使用[626:439638] download4----<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.214 NSOperation基本使用[626:439638] op4执行完毕---<NSThread: 0x17da2b00>{number = 6, name = (null)}2016-10-11 17:56:04.215 NSOperation基本使用[626:439625] download3----<NSThread: 0x17e9a830>{number = 5, name = (null)}

0 0