NSOperation、NSOperationQueue是对GCD的进一步封装,比GCD简单易用、更易读;
为什么使用NSOperation
1、NSOperation可以设置任务之间的依赖关系;
2、NSOperation可以设置任务的优先级;
3、NSOperaion可以获取任务当前的状态isFinished(已完成)、isCancelled(已取消)、isExecuteing(正在执行)
1、NSOperaion、NSOperationQueue操作和操作队列
1.1 NSOperation操作
通过NSOperation的子类NSBlockOperation和NSInvotionOperaion或者自定义创建操作
需要注意的是,如果操作没有添加到操作队列中,需要调用start方法执行任务,如果添加到队列中,不需要调用start方法
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
}];
[operation start];
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation) object:nil];
[operation2 start];
2、NSOperationQueue
NSOperationQueue通过设置最大并发数
,来确定是串行队列还是并发队列
(1)默认情况下最大并发数是-1,不限制开辟线程数;
(2)当最大并发数为1时,为串行队列;
(3)当最大并发数大于1时,为并发队列;
maxConcurrentOperationCount = 0,不执行。默认是maxConcurrentOperationCount = -1,异步队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 0;
2.1将操作添加到操作队列中
将操作添加到操作队列中有两种
方式
第一种
addOperation,创建操作后,将操作添加到队列
[queue addOperation:operation];
第二种
addOperationWithBlock,直接添加任务,不需要创建操作
[queue addOperationWithBlock:^{
NSLog(@"执行操作");
}];
3、创建依赖
下面表示operation依赖operation2操作,operation2操作完成后operation操作才会执行
需要注意的是,先添加依赖关系,再将操作添加到操作队列中,否则依赖关系不起作用
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
}];
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocation) object:nil];
[operation addDependency:operation2];
[queue addOperation:operation];
[queue addOperation:operation2];
4、优先级
NSOperaion可以通过设置优先级,改变操作执行顺序,默认情况下,操作的优先级是NSOperationQueuePriorityNormal
, 我们可以通过setQueuePriority
方法设置操作的优先级
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
如果一个操作队列中既设置了优先级,也设置了依赖关系,有限执行已经准备就绪的操作,如果当前有op1、op2、op3、op4四个操作添加到队列中,op2依赖于op1,op3依赖于op2,op1和op4都没有依赖,那么op1和op4处于准备就绪状态,op2和op3处于未准备就绪状态,如果op4的优先级高于op1,当最大并发数为1的情况下那么执行顺序是op4、op1、op2、op3;如果op2或者op3的优先级高于op4,执行顺序还是如此。如果最大并发数不为1,那么执行顺序为op4、op1、op2、op3或op1、op4、op2、op3.
5、线程间的通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1===%@", [NSThread currentThread]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"回到主线程刷新界面");
}];
}];
[queue addOperation:operation1];
6、线程安全
6.1NSOperation、NSOperationQueue 非线程安全
下面,我们模拟火车票售卖的方式,实现 NSOperation 线程安全和解决线程同步问题。
场景:总共有100张火车票,有两个售卖火车票的窗口,一个是广东火车票售卖窗口,另一个是广西火车票售卖窗口。两个窗口同时售卖火车票,卖完为止。
/**
* 非线程安全:不使用 NSLock
* 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票
*/
- (void)initTicketStatusNotSave {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
self.ticketSurplusCount = 50;
// 1.创建 queue1,queue1 代表广东火车票售卖窗口
NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];
queue1.maxConcurrentOperationCount = 1;
// 2.创建 queue2,queue2 代表广西火车票售卖窗口
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
queue2.maxConcurrentOperationCount = 1;
// 3.创建卖票操作 op1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicketNotSafe];
}];
// 4.创建卖票操作 op2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[self saleTicketNotSafe];
}];
// 5.添加操作,开始卖票
[queue1 addOperation:op1];
[queue2 addOperation:op2];
}
/**
* 售卖火车票(非线程安全)
*/
- (void)saleTicketNotSafe {
while (1) {
if (self.ticketSurplusCount > 0) {
//如果还有票,继续售卖
self.ticketSurplusCount--;
NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);
[NSThread sleepForTimeInterval:0.2];
} else {
NSLog(@"所有火车票均已售完");
break;
}
}
}
6.2线程安全,加线程锁(使读写操作在同一线程操作,才能保证线程安全。atomic只是保证读写安全)
- (void)saleTicketNotSafe {
while (1) {
[self.lock lock];
if (self.ticketSurplusCount > 0) {
//如果还有票,继续售卖
self.ticketSurplusCount--;
NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);
[NSThread sleepForTimeInterval:0.2];
} else {
NSLog(@"所有火车票均已售完");
break;
}
[self.lock unlock];
}
}
网友评论