简介
NSOperation,NSOperationQueue是在GCD基础上的封装,面向对象
基本使用
NSOperation是个抽象类,不能用来封装操作.只有使用它的子类来封装操作.有三种方式来封装操作
- 使用子类
NSInvocationOperation - 使用子类
NSBlockOperation - 自定义继承自
NSOperation的子类,通过实现内部相应的方法来封装操作
1. NSInvocationOperation
- 单独使用 NSInvocationOperation
#创建NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:NULL];
#启动
[operation start];
⚠️ 单独使用NSInvocationOperation,而没有使用NSOperationQueue,并不会创建线程,只会在当前线程执行任务
2. 单独使用NSBlockOperation
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]); // 当前线程
}];
[operation start];
⚠️ 同样单独使用NSBlockOperation,一样不会创建线程,只在当前线程执行
- NSBlockOperation 使用addExecutionBlock,那么添加的block有可能会开辟新线程执行
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]); // 当前线程
}];
[operation addExecutionBlock:^{
NSLog(@"%@",[NSThread currentThread]); // 新线程
}];
[operation start];
3.自定义NSOperation有两种
可以通过重写
main或者start方法 来定义自己的 NSOperation 对象。重写main方法比较简单,我们不需要管理操作的状态属性isExecuting和isFinished。当main执行完返回的时候,这个操作就结束了 重写start可以参考这个
⚠️ 单独使用NSOperation一样只会在当前线程执行,不会创建新的线程
4.使用NSOperationQueue
- 主队列,在主队列中的任务都会在主线程执行
NSOperationQueue *queue = [NSOperationQueue mainQueue];
- 自定义队列创建方法,在自定义的队列中会在子线程执行任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
-(void)operationQueue
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:NULL];
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]); // <NSThread: 0x600001ee98c0>{number = 5, name = (null)}
}];
[queue addOperation:invOperation];
[queue addOperation:blockOperation];
[queue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]); // <NSThread: 0x600001eac640>{number = 6, name = (null)}
}];
}
-(void)run
{
NSLog(@"%@",[NSThread currentThread]); // <NSThread: 0x600001ee8a40>{number = 3, name = (null)}
}
- NSOperationQueue 控制串行,并发队列(maxConcurrentOperationCount为1时串行队列,不为1时并发队列)
-(void)operationQueue
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1; // 串行队列
[queue addOperationWithBlock:^{
NSLog(@"1 - %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"2 - %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"3 - %@",[NSThread currentThread]);
}];
}
#打印
1 - <NSThread: 0x6000005401c0>{number = 6, name = (null)}
2 - <NSThread: 0x6000005401c0>{number = 6, name = (null)}
3 - <NSThread: 0x6000005401c0>{number = 6, name = (null)}
- 依赖操作
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *block01 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1 - %@",[NSThread currentThread]);
}];
NSBlockOperation *block02 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2 - %@",[NSThread currentThread]);
}];
NSBlockOperation *block03 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3 - %@",[NSThread currentThread]);
}];
[block02 addDependency:block01];
[block03 addDependency:block02];
[queue addOperation:block01];
[queue addOperation:block02];
[queue addOperation:block03];
#打印
1 - <NSThread: 0x600001a8c480>{number = 6, name = (null)}
2 - <NSThread: 0x600001a8c480>{number = 6, name = (null)}
3 - <NSThread: 0x600001a8c480>{number = 6, name = (null)}
- 线程通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]); //<NSThread: 0x600000223180>{number = 5, name = (null)}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]); //<_NSMainThread: 0x600000270800>{number = 1, name = main}
}];
}];
- 卖票案例
-(void)initSaleSiticket
{
self.ticketCount = 20;
__weak typeof(self) weakSelf = self;
// A窗口卖票线程
NSOperationQueue *saleWindowAQueue = [[NSOperationQueue alloc] init];
saleWindowAQueue.maxConcurrentOperationCount = 1;
saleWindowAQueue.name = @"A窗口";
[saleWindowAQueue addOperationWithBlock:^{
[weakSelf saleSicketAction];
}];
// B窗口卖票线程
NSOperationQueue *saleWindowBQueue = [[NSOperationQueue alloc] init];
saleWindowBQueue.maxConcurrentOperationCount = 1;
saleWindowBQueue.name = @"B窗口";
[saleWindowBQueue addOperationWithBlock:^{
[weakSelf saleSicketAction];
}];
}
-(void)saleSicketAction
{
while (YES) {
[self.lock lock];
if (self.ticketCount > 0) {
self.ticketCount--;
NSLog(@"%@ : %ld",[NSThread currentThread].name,(long)self.ticketCount);
} else {
NSLog(@"票卖完了");
break;
}
[self.lock unlock];
[NSThread sleepForTimeInterval:1.0];
}
}