文档章节

iOS 多线程之NSOperation篇举例详解

张林峰
 张林峰
发布于 2016/06/22 11:24
字数 1424
阅读 12
收藏 0

  这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇。总篇也包含了此文的链接。本文讲解的知识点有NSBlockOperationClick,队列,队列中如何加Operation,Operation中如何加任务,Operation之间的串行、并行,监控任务完成时机及其他一些关于NSOperation的方法,每个知识点都有例子和详细分析。附上demo下载地址

一、NSOperation介绍

  NSOperation 是苹果公司对 GCD 的封装,完全面向对象。NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作。NSOperation本身是抽象基类,因此可以使用它的子类NSInvocationOperation 和 NSBlockOperation,或者自定义子类也行。NSOperation 和 NSOperationQueue 可以看成是GCD的任务和队列。

二、NSInvocationOperation(不是类型安全的,苹果在swift里不用它了)

  但是我还是来讲讲,证明它曾经存在过。NSInvocationOperation创建一个 Operation 后,需要调用 start 方法来启动任务,它会 默认在当前队列同步执行。举个例子

- (IBAction)NSInvocationOperationClick:(id)sender {
    //1.创建NSInvocationOperation对象
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTask) object:nil];
    operation.completionBlock = ^() {
        NSLog(@"执行完毕");
    };
    //2.在当前线程执行
    [operation start];
    NSLog(@"阻塞我没有?当前线程%@",[NSThread currentThread]);
}

//模拟很耗时的任务
-(void)myTask {
    for (NSInteger i = 0; i < 500000000; i++) {
        if (i == 0) {
            NSLog(@"任务 -> 开始");
        }
        if (i == 499999999) {
            NSLog(@"任务 -> 完成");
        }
    }
}

 

打印结果:

分析结论:从打印结果看,会阻塞当前线程,因为他是同步执行的。

三、NSBlockOperationClick

  在block中加任务,使用更方便,代码更紧凑,举个例子。

- (IBAction)NSBlockOperationClick:(id)sender {
    //1.创建NSBlockOperation对象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [self myTask];
    }];
    
    //2.也可以添加多个Block,通过这个方法可以给 Operation 添加多个执行 Block。这样 Operation 中的任务 会并发执行,它会 在主线程和其它的多个线程 执行这些任务
    for (NSInteger n = 0; n < 3; n++) {
        [operation addExecutionBlock:^{
            for (NSInteger i = 0; i < 500000000; i++) {
                if (i == 0) {
                    NSLog(@"任务%ld -> 开始",n);
                }
                if (i == 499999999) {
                    NSLog(@"任务%ld -> 完成",n);
                }
            }
        }];
    }
    operation.completionBlock = ^() {
        NSLog(@"执行完毕");
    };
    //3.开始任务
    [operation start];
    NSLog(@"阻塞我没有?当前线程%@",[NSThread currentThread]);
}

打印结果:

分析结论:给 Operation 添加多个执行 Block任务,Operation 中的任务会并发执行,它会在主线程和其它的多个线程执行这些任务,会阻塞当前主线程。

四、主队列

  举个例子

//主队列里的任务并行执行,且不阻塞当前线程。(队列中加多个operation时另说,看第五个例子就知道了)
- (IBAction)mainQueue:(id)sender {
    NSOperationQueue *queue = [NSOperationQueue mainQueue];
    //创建NSBlockOperation对象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [self myTask];
    }];
    for (NSInteger n = 0; n < 3; n++) {
        [operation addExecutionBlock:^{
            for (NSInteger i = 0; i < 500000000; i++) {
                if (i == 0) {
                    NSLog(@"主队列中任务%ld -> 开始%@",n,[NSThread currentThread]);
                }
                if (i == 499999999) {
                    NSLog(@"主队列中任务%ld -> 完成",n);
                }
            }
        }];
    }
    operation.completionBlock = ^() {
        NSLog(@"执行完毕");
    };
    //加入到队列中任务自动执行
    [queue addOperation:operation];
    NSLog(@"阻塞我没有?当前线程%@",[NSThread currentThread]);
}

打印结果:

分析结论:主队列里的任务都是另开线程并行执行的,不会阻塞当前线程。(队列中加多个operation时另说,请看下面例子)

五、其他队列

  基本用法跟主队列差不多,我将在这个例子里列举更多用法。在一个队列里加2个operation,第一个operation里加2个任务。举个例子

- (IBAction)otherQueue:(id)sender {
    //1.创建一个其他队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //最大并发数,用来设置最多可以让多少个operation同时执行。当你把它设置为 1 的时候,就是串行了(指多个operation的串行,同一个operation中的任务是并行的)
    queue.maxConcurrentOperationCount = 1;
    
    //2.创建NSBlockOperation对象
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 0) {
                NSLog(@"operation1中任务1 -> 开始");
            }
            if (i == 499999999) {
                NSLog(@"operation1中任务1 -> 完成");
            }
        }
    }];
    
    //3.给operation1再加一个任务
    [operation1 addExecutionBlock:^{
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 0) {
                NSLog(@"operation1中任务2 -> 开始");
            }
            if (i == 499999999) {
                NSLog(@"operation1中任务2 -> 完成");
            }
        }
    }];
    operation1.completionBlock = ^() {
        NSLog(@"执行完毕");
    };
    
    //4.再加一个operation2
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 0) {
                NSLog(@"operation2中任务 -> 开始");
            }
            if (i == 499999999) {
                NSLog(@"operation2中任务 -> 完成");
            }
        }
    }];
    
    //5.加入到队列中任务自动执行,waitUntilFinished为yes会阻塞当前线程,为no不阻塞
    [queue addOperations:@[operation1,operation2] waitUntilFinished:NO];
    NSLog(@"阻塞我没有?当前线程%@",[NSThread currentThread]);
}

打印结果:

分析结论:2个operation是串行的,但同一个operation中的多个任务是并行的

六、任务依赖

  任务一完成的情况下才能执行任务二,任务二完成的情况下才能执行任务三,举个例子。

//任务依赖
- (IBAction)addDependency:(id)sender {
    //1.任务一
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务1开始");
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任务1完成");
    }];
    //2.任务二
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务2开始");
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任务2完成");
    }];
    //3.任务三
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务3开始");
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任务3完成");
    }];
    //4.设置依赖
    [operation2 addDependency:operation1];      //任务二依赖任务一
    [operation3 addDependency:operation2];      //任务三依赖任务二
    //5.创建队列并加入任务
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
}

打印结果:

分析结论:该任务依赖的任务完成了,才能执行该任务。

七、其他相关方法

// 暂停queue
[queue setSuspended:YES];

// 继续queue
[queue setSuspended:NO];
 //会阻塞当前线程,等到某个operation执行完毕
[operation waitUntilFinished];
// 阻塞当前线程,等待queue的所有操作执行完毕
[queue waitUntilAllOperationsAreFinished];
// 取消单个操作
[operation cancel];
// 取消queue中所有的操作
[queue cancelAllOperations];

 

© 著作权归作者所有

张林峰
粉丝 0
博文 10
码字总数 9529
作品 0
徐汇
高级程序员
私信 提问
关于iOS多线程,这边勉强可以看看(OC&Swift)

iOS开发多线程总是绕不过的坎,看了很多前辈们优秀的文章,如:关于iOS多线程,我说,你听,没准你就懂了!、谈iOS多线程(NSThread、NSOperation、GCD)编程、iOS多线程:『GCD』详尽总结、i...

Andy_Ron
2018/08/26
0
0
【书坊赠书福利——第二期】《iOS 8开发指南》

本周是人邮IT书坊赠书的第二期,第一期参与度极高,微信君在此感谢你们的支持,第一期获奖赠书已全部寄出。 本周赠品 本周,微信君给大家推荐@人民邮电出版社-信息技术分社 刚刚上架的新书《...

生气的散人
2014/09/23
387
0
iOS多线程编程之NSOperation和NSOperationQueue的使用

目录(?)[-] iOS多线程编程之NSThread的使用 使用 NSOperation的方式有两种 一种是用定义好的两个子类 另一种是继承NSOperation NSInvocationOperation例子 第二种方式继承NSOperation 如何控...

malawo
2013/09/05
30
0
ios 多线程 网络编程

如何在IOS中实现多线程网络编程,实现两个线程并发访问一个资源,我在数据连接类中实现了 NSURLConnectionDataDelegate,但是试了NSOPeration和GCD的方法,都没有成功,求高人指点迷津,谢谢...

七伽杜
2016/01/15
144
2
iOS开发系列--并行开发其实很容易

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jianxin160/article/details/47753225 --多线程开发 概览 大家都知道,在开发过程中应该尽可能减少用户等待时...

KenshinCui
2015/08/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

关于AsyncTask的onPostExcute方法是否会在Activity重建过程中调用的问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/XG1057415595/article/details/86774575 假设下面一种情况...

shzwork
今天
6
0
object 类中有哪些方法?

getClass(): 获取运行时类的对象 equals():判断其他对象是否与此对象相等 hashcode():返回该对象的哈希码值 toString():返回该对象的字符串表示 clone(): 创建并返此对象的一个副本 wait...

happywe
今天
6
0
Docker容器实战(七) - 容器中进程视野下的文件系统

前两文中,讲了Linux容器最基础的两种技术 Namespace 作用是“隔离”,它让应用进程只能看到该Namespace内的“世界” Cgroups 作用是“限制”,它给这个“世界”围上了一圈看不见的墙 这么一...

JavaEdge
今天
8
0
文件访问和共享的方法介绍

在上一篇文章中,你了解到文件有三个不同的权限集。拥有该文件的用户有一个集合,拥有该文件的组的成员有一个集合,然后最终一个集合适用于其他所有人。在长列表(ls -l)中这些权限使用符号...

老孟的Linux私房菜
今天
7
0
面试套路题目

作者:抱紧超越小姐姐 链接:https://www.nowcoder.com/discuss/309292?type=3 来源:牛客网 面试时候的潜台词 抱紧超越小姐姐 编辑于 2019-10-15 16:14:56APP内打开赞 3 | 收藏 4 | 回复24 ...

MtrS
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部