iOS 开发 多线程详解之NSOperation实现多线程
来源:互联网 发布:柏拉图交友软件 编辑:程序博客网 时间:2024/05/22 16:53
NSOperation简介
@interface NSOperation : NSObject
1.他是一个抽象类,无法直接使用.但是我们可以使用它的子类.作为父类约束子类共有的属性和方法
2.子类 - 操作默认是异步的.
NSBlockOperation
NSInvocationOperation
自定义NSOperation
3.队列 - 默认是并发的.
@interface NSOperationQueue : NSObject
4.总结
GCD的核心 : 将任务添加到队列
NSOperation的核心 : 将操作添加到队列
5.使用步骤
1.先将需要执行的操作封装到一个NSOperation对象中.创建NSOperation对象.2.将NSOperation对象添加到NSOperationQueue中.3.NSOperationQueue会自动将NSOperation取出来.4.将取出的NSOperation封装的操作自动放到一条对应的新线程中执行.
NSOperation的属性和方法
//- (void)start;//- (void)main;//操作取消@property (readonly, getter=isCancelled) BOOL cancelled;- (void)cancel;//操作执行@property (readonly, getter=isExecuting) BOOL executing;//操作结束@property (readonly, getter=isFinished) BOOL finished;//并发操作@property (readonly, getter=isConcurrent) BOOL concurrent; //异步操作@property (readonly, getter=isAsynchronous) BOOL asynchronous ;//操作依赖关系的添加和删除--操作可以'跨队列'依赖- (void)addDependency:(NSOperation *)op;- (void)removeDependency:(NSOperation *)op;@property (readonly, copy) NSArray<NSOperation *> *dependencies;//队列优先级@property NSOperationQueuePriority queuePriority;//线程优先级@property double threadPriority ;//服务质量@property NSQualityOfService qualityOfService ;//操作属性名@property (nullable, copy) NSString *name;
NSOperationQueue的属性和方法
//队列添加操作- (void)addOperation:(NSOperation *)op;- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;//最常用的添加操作到队列的方法- (void)addOperationWithBlock:(void (^)(void))block ;//多个操作@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;//队列的操作计数--保存未执行/未执行完的操作个数@property (readonly) NSUInteger operationCount ;//队列的最大并发数--限制**同时执行**的操作数.@property NSInteger maxConcurrentOperationCount;//队列的挂起--暂停(正在执行的操作无法被暂停)@property (getter=isSuspended) BOOL suspended;//队列的名称@property (nullable, copy) NSString *name ;//操作的优先级 : 不决定顺序,只改变概率@property NSQualityOfService qualityOfService ;//取消所有操作--正在执行的操作无法取消- (void)cancelAllOperations;- (void)waitUntilAllOperationsAreFinished;//当前队列@property (class, readonly, strong, nullable) NSOperationQueue *currentQueue ;//最队列@property (class, readonly, strong) NSOperationQueue *mainQueue;
子类:NSInvocationOperation
//基本没什么功能,很少有人用- (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;- (instancetype)initWithInvocation:(NSInvocation *)inv;@property (readonly, retain) NSInvocation *invocation;@property (nullable, readonly, retain) id result;
//和NSThread用法有些类似,都需要alloc init 去添加target和selector---操作和要执行的任务是分开的- (void)opDemo3{ // 队列 : 默认是并发的 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 循环的向队列中添加10个操作 for (int i = 0; i < 10; i++) { // 操作对象 : OP中的操作对象默认是异步执行 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@(i)]; // 将操作添加到队列 [queue addOperation:op]; }}- (void)demo:(id)parram{ // 查看当前线程 NSLog(@"%@ %@",parram,[NSThread currentThread]);}
- 执行效果 : 会开启多条线程,不是顺序执行.与GCD中并发队列&异步执行效果一样
- 队列 : 默认是并发的
子类:NSBlockOperation
属性
//直接在block块里添加需要执行的操作,很方便+ (instancetype)blockOperationWithBlock:(void (^)(void))block;- (void)addExecutionBlock:(void (^)(void))block;@property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;
基本用法
- (void)OPDemo2{ // 创建队列 : 队列默认是并发的 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; for (NSInteger i = 0; i < 100; i++) { // 创建操作 : 默认是异步的 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%zd %@",i,[NSThread currentThread]); }]; // 把操作添加到队列 [queue addOperation:op]; }}
开发中的用法
- NSOperationQueue只有一种类型.就是并发队列.
- 在实际开发时,如果要使用到NSOperationQueue,可以直接定义成全局的队列
@interface ViewController ()/// 开发中会定义一个全局的并发队列@property (nonatomic, strong) NSOperationQueue *queue;@end
//懒加载- (NSOperationQueue *)queue { if (_queue == nil) { _queue = [[NSOperationQueue alloc] init]; } return _queue;}
#pragma mark - OP的简写- (void)OPDemo3 { [self.queue addOperationWithBlock:^{ NSLog(@"子线程中执行的操作 %@",[NSThread currentThread]); }];}
线程间通信
#pragma mark - OP的线程间的通信- (void)OPDemo4{ // 在子线程执行下载的操作 [self.queue addOperationWithBlock:^{ NSLog(@"子线程中执行下载的操作 %@",[NSThread currentThread]); // 如果下载结束,就回到主线程刷新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"刷新UI %@",[NSThread currentThread]); }]; }];}
maxConcurrentOperationCount 最大并发数
NSOperation封装的是GCD也有可调度线程池,会重用线程
@interface ViewController ()@property (nonatomic, strong) NSOperationQueue *queue;@end@implementation ViewController- (NSOperationQueue *)queue { if (_queue == nil) { _queue = [[NSOperationQueue alloc] init]; // 设置队列的最大并发数 : 保证了队列最多可以同时调度2个操作同时执行,"间接"控制了线程的数量 _queue.maxConcurrentOperationCount = 2; } return _queue;} - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self OPDemo1];}- (void)OPDemo1 { for (NSInteger i = 0; i < 50; i++) { NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ // 模拟延迟 : 让设置最大并发数之后的执行效果更佳的明显 [NSThread sleepForTimeInterval:1.0]; NSLog(@"%zd %@",i,[NSThread currentThread]); }]; [self.queue addOperation:op]; }}
执行的结果 : 任务是两个两个的执行.
队列的暂停继续和取消全部
- (BOOL)isSuspended;暂停和继续队列的属性.
- YES代表暂停队列,NO代表恢复队列.
- cancelAllOperations : 取消队列中的全部操作.
- cancel : 取消队列中的单个操作.
@interface ViewController ()@property (nonatomic, strong) NSOperationQueue *queue;@end@implementation ViewController- (NSOperationQueue *)queue { if (_queue == nil) { _queue = [[NSOperationQueue alloc] init]; // 设置队列的最大并发数 : 保证了队列最多可以同时调度2个操作同时执行,"间接"控制了线程的数量 _queue.maxConcurrentOperationCount = 2; } return _queue;}#pragma mark - 暂停/* 1.正在执行的操作无法被暂停 2.队列的操作计数 : operationCount;保存的是没有执行完的操作,已经执行完的操作不会被计数在内 3.一旦先把队列挂起,再往里面添加操作,这个操作是可以成功的添加进去的,但是不会被调度执行 */- (IBAction)zanting:(id)sender { // 当队列里面没有操作时,就不让暂停/不让挂起队列 if (self.queue.operationCount == 0) { return; } // 是队列暂停调度任务 self.queue.suspended = YES; NSLog(@"暂停 %tu",self.queue.operationCount);}
- 将队列挂起之后,队列中的操作就不会被调度,但是正在执行的操作不受影
- operationCount:操作计数,没有执行和没有执行完的操作,都会计算在操作计数之内
- 注意 : 如果先暂停队列,再添加操作到队列,队列不会调度添加的操作.所以在暂停队列之前要判断队列中有没有任务.如果没有任务就不暂停队列.
#pragma mark - 继续- (IBAction)jixu:(id)sender { // 是队列继续调度任务 self.queue.suspended = NO; NSLog(@"继续 %tu",self.queue.operationCount);}
#pragma mark - 取消全部// 正在执行的操作不会被取消// 提示 : 如果非要取消正在执行的操作,就需要自定义NSOperation- (IBAction)cancelAll:(id)sender { // 取消队列里面所有的操作 [self.queue cancelAllOperations]; // 提示 : 取消全部的操作是有延迟的 // 休眠的目的是为了演示延迟操作 [NSThread sleepForTimeInterval:2.0]; NSLog(@"取消全部 %tu",self.queue.operationCount);}
- 一旦调用的 cancelAllOperations方法,队列中的操作,都会被移除,正在执行的操作除外.
- 正在执行的操作取消不了,如果要取消,需要自定义队列.
操作优先级和监听操作完成回调
- 操作的优先级 : qualityOfService
无法决定操作执行的先后顺序的,决定的是操作有更多的机会被队列调度执行. - 监听操作完成的回调 : @property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);
当操作执行结束之后,就会回调,是在子线程中执行的.
- (void)opDemo{ // 操作1 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 10; i++) { // 查看当前线程 NSLog(@"op1 %@",[NSThread currentThread]); } }]; //设置操作的优先级 op1.qualityOfService = NSQualityOfServiceUserInteractive; // 当操作执行结束之后,就会回调,是在子线程中执行的 [op1 setCompletionBlock:^{ // 查看当前线程 NSLog(@"操作结束了 %@",[NSThread currentThread]); }]; [self.queue addOperation:op1]; // 操作2 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 10; i++) { // 查看当前线程 NSLog(@"op2 %@",[NSThread currentThread]); } }]; op2.qualityOfService = NSQualityOfServiceBackground; [self.queue addOperation:op2];}
操作间依赖
需求 : 登陆–>付费–>下载–>通知用户
#pragma mark - 操作依赖- (void)dependency{ NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"登陆 %@",[NSThread currentThread]); }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"付费 %@",[NSThread currentThread]); }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下载 %@",[NSThread currentThread]); }]; NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"通知用户 %@",[NSThread currentThread]); }];}
建立依赖关系 : 不能循环建立操作间依赖关系.否则,队列不调度操作执行
// 操作2依赖操作1[op2 addDependency:op1];[op3 addDependency:op2];[op4 addDependency:op3];// 不能循环依赖 : 操作不会被调度// [op1 addDependency:op4];// waitUntilFinished : 是否等到指定的操作执行结束再执行后面的代码[self.queue addOperations:@[op1,op2,op3,op4] waitUntilFinished:NO];// 验证 waitUntilFinishedNSLog(@"end");
建立依赖关系 : 操作间可以跨队列建立依赖关系
// 操作2依赖操作1[op2 addDependency:op1];[op3 addDependency:op2];[op4 addDependency:op3];// 不能循环依赖 : 操作不会被调度// [op1 addDependency:op4];// waitUntilFinished : 是否等到指定的操作执行结束再执行后面的代码[self.queue addOperations:@[op1,op2,op3] waitUntilFinished:NO];// 通知用户的操作在主线程中执行// 操作可以跨队列依赖[[NSOperationQueue mainQueue] addOperation:op4];// 验证 waitUntilFinishedNSLog(@"end");建立依赖关系 : 要将操作间的依赖建立好了之后,再添加到队列中
0 0
- iOS 开发 多线程详解之NSOperation实现多线程
- IOS多线程开发之NSOperation
- iOS开发 - 多线程之NSOperation
- iOS多线程开发之NSOperation
- IOS开发 - 多线程 NSOperation
- ios多线程开发——nsoperation详解
- iOS开发多线程-NSOperation \ GCD详解
- iOS多线程之NSOperation
- iOS多线程之NSOperation
- iOS多线程之NSOperation
- ios多线程之NSOperation
- IOS多线程之NSOperation
- iOS多线程之NSOperation
- iOS --- 多线程之NSOperation
- iOS-多线程之NSOperation
- iOS -- 多线程之NSOperation
- iOS多线程之NSOperation
- IOS多线程之NSOperation
- unity之shader学习笔记(四)--高光反射
- 最短路径(2)--poj1797(Dijkstra变形题)
- OpenCV2.3+Visual Studio 2008开发环境配置
- 代码实现验证码
- hadoop的体系结构
- iOS 开发 多线程详解之NSOperation实现多线程
- NYOJ-86 找球号(一)
- hhu1003 数字整除 大数取余
- WebDriverException:Message:'geckodriver'executable needs to be in Path
- Java中Synchronized的用法
- Ubuntu14.04安装搜狗输入法
- python中selenium操作下拉滚动条方法汇总
- 初始反射
- Java 字体颜色转换工具类 ColorUtil