您的位置:首页 > 运维架构

多线程 (五)NSOperation

2016-02-09 12:54 330 查看
NSOperation是对GCD的分装,OC语言,更简单方便

NSOperation和NSOperationQueue一起使用也能实现多线程编程

基本步骤:

将操作封装到一个NSOperation对象中

将NSOperation对象添加到NSOperationQueue队列

系统会将NSOperationQueue中的NSOperation取出

将取出的NSOperation封装的操作放到一条新线程中执行

NSOperation是一个抽象类,不具备操作能力,必须使用它的子类:

NSInvocationOperation

NSBlockOperation(使用的最多)

自定义子类继承于NSOperation,实现相应的方法(使用较少)

1.NSInvocationOperation:

- (void)InvocationOperation
{
//创建队列,通过alloc init方式创建的队列是并发队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

   for(int i = 0; i < 5; i++)
{
//创建操作
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];
//把操作放到队列中
[queue addOperation:op];
}
}

- (void)test
{
NSLog(@"当前线程 = %@",[NSThread currentThread]);
}


打印可以验证queue是一个并发队列



2.NSBlockOperation

- (void)BlockOperation
{
//创建队列,通过alloc init方式创建的队列是并发队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

for(int i = 0; i < 5; i++)
{
//创建操作
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"当前线程 = %@",[NSThread currentThread]);
}];
//把操作放到队列中
[queue addOperation:op];
}
}


也可以这样使用(更简单)

- (void)BlockOperationEasy
{
//创建队列,通过alloc init方式创建的队列是并发队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"当前线程 = %@",[NSThread currentThread]);
}];
}


添加一个额外的操作

- (void)BlockOperation
{
//创建队列,通过alloc init方式创建的队列是并发队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//创建操作
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"当前线程 = %@",[NSThread currentThread]);
}];
//再添加一个操作
[op addExecutionBlock:^{
NSLog(@"这是一个额外的操作,线程 = %@",[NSThread currentThread]);
}];
//把操作放到队列中
[queue addOperation:op];

}


NSOperationQueue:

NSOperationQueue没有串行队列,但是它可以获取主队列,通过下面代码获取到主队列,添加到主队列中的任务都会在主线程中执行

[NSOperationQueue mainQueue]


线程间通讯 :

- (void)refreshUI
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"多线程中执行的操作%@",[NSThread currentThread]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"回到主线程更新UI%@",[NSThread currentThread]);
}];
}];
}


最大并发数:

并发数是指同时执行任务的数量

比如同时开启3个线程执行3个任务,并发数就是3

NSOperation可以通过最大并发数控制同一时间执行操作数量

- (void)max
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 2;
for (int i = 0; i< 10; i++)
{
[queue addOperationWithBlock:^{
NSLog(@"i = %d, thread = %@",i,[NSThread currentThread]);
}];
}
}


结果出现了2,3,4,5四个线程,这是因为最大并发决定的是同一时间执行操作数量,而不是线程的数量;



挂起队列:

挂机队列是把任务保存在当前状态,之后可以继续

挂起操作不会影响已经在执行的任务

- (void)suspended
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for (int i = 0; i< 10; i++)
{
if (i == 5)
{
//挂起队列
queue.suspended = YES;
//延迟2s
[NSThread sleepForTimeInterval:2];
//继续
queue.suspended = NO;
}
[queue addOperationWithBlock:^{

NSLog(@"i = %d, thread = %@",i,[NSThread currentThread]);
}];
}
}


取消操作

取消操作并不会影响队列的挂起状态

(如果队列是挂起状态)一般取消操作后会把队列置于不挂起状态,便于后续操作

挂起队列,队列中的任务还存在,可以继续;取消操作,队列中的任务就没有了,只能重新添加任务

- (void)cancel
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//设置最大并发数为1
queue.maxConcurrentOperationCount = 1;
for (int i = 0; i< 10; i++)
{
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1];
NSLog(@"i = %d, thread = %@",i,[NSThread currentThread]);
}];
}
//3S后取消队列里的所有操作
[NSThread sleepForTimeInterval:3];
[queue cancelAllOperations];
}


打印结果可以看出后面的操作都已经被取消了



依赖关系 :

依赖关系可以跨队列

注意不要循环依赖

- (void)dependecy
{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *one = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载音乐");
}];
NSBlockOperation *two = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打开音乐");
}];
NSBlockOperation *three = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"播放音乐");
}];
//添加任务依赖关系
[two addDependency:one];
[three addDependency:two];

//等待任务完成继续下一个任务,类似于GCD里的调度组
[queue addOperations:@[one,two,three] waitUntilFinished:YES];
NSLog(@"听完音乐放松一下");
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: