您的位置:首页 > 移动开发 > IOS开发

iOS 多线程(三)NSOperation

2016-10-13 13:45 197 查看
NSOperation多线程任务类,是个“抽象类”,并不具备封装操作的能力,必须使用它的子类。

使用NSOperation子类的三种方法:

NSInvocationOperation
NSBlockOperation
自定义子类继承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,则会异步执行任务。
添加方式:

- (void)addOperation:(NSOperation *)op;
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
- (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:-1
2016-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
可以在不同queue的NSOperation之间创建依赖关系,但是不能相互依赖,比如A依赖B,B依赖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)}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: