1.NSOperation的基本操作

使用NSOperation的两个子类,NSInvocationOperation 和 NSBlockOperation 创建操作,然后将操作添加到队列中去执行

// NSOperation

    // 1. 实例化 NSOperation 子类对象:NSInvocationOperation
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test1) object:nil]; // 2. 实例化 NSOperation 子类对象
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
//
NSLog(@"耗时操作2------------");
}]; // NSOperationQueue // 1.获取主队列
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; // 2.创建非主队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // NSOperation使用: 将操作添加到队列中!
[mainQueue addOperation:op]; [queue addOperation:op1];

2.NSOperation定义的操作可以直接用start启动,相当于直接执行,入口是NSOperation中定义的main方法

    // 1. 实例化操作对象
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test1) object:nil]; NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test2) object:nil]; NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test3) object:nil]; // 需求: 1. 三个操作都是耗时操作! // // 2. 创建非主队列
// NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//
// // 3. 将操作添加到非主队列中
// [queue addOperation:op1];
// [queue addOperation:op2];
// [queue addOperation:op3]; // // 需求: 2. 三个操作都是UI操作
// NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
// // 相当于 GCD 中的 异步函数 + 主队列!
// [mainQueue addOperation:op1];
// [mainQueue addOperation:op2];
// [mainQueue addOperation:op3]; // NSOperation 执行方式2: 直接启动!直接在当前线程执行!
[op1 start];
[op2 start];
[op3 start]; // NSOperation 对象的入口是定义在自身内部的 main 方法;
// 当将操作添加到操作队列中或者直接调用操作的 start 方法之后,内部都会调用 main 方法,所有两者都能够执行操作! NSLog(@"touchesEnd"); } - (void)test1
{
NSLog(@"test1----------%@",[NSThread currentThread]);
} - (void)test2
{
NSLog(@"test2----------%@",[NSThread currentThread]);
} - (void)test3
{
NSLog(@"test3----------%@",[NSThread currentThread]);
}

3.使用block

NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"222222222----%@",[NSThread currentThread]);
}]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"33333333----%@",[NSThread currentThread]);
}]; // 1.将操作添加到主队列中
// [[NSOperationQueue mainQueue] addOperation:op1];
// [[NSOperationQueue mainQueue] addOperation:op2];
// [[NSOperationQueue mainQueue] addOperation:op3]; NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];

4.向blockOperation中追加任务

// 当 NSBlockOperation中的任务数 > 1 之后, 无论是将操作添加到主线程,还是在主线程直接执行 start ,NSBlockOperation中的任务执行顺序都不确定,执行线程也不确定!

// 一半在开发的时候,要避免向 NSBlockOperation 中追加任务!

// 如果任务都是在子线程中执行,并且不需要保证执行顺序,可以直接追加任务!

// 1. 实例化操作对象
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"11111111----%@",[NSThread currentThread]);
}]; // 往当前操作中追加操作
[op1 addExecutionBlock:^{ NSLog(@"追加任务1%@",[NSThread currentThread]); }]; // 往当前操作中追加操作
[op1 addExecutionBlock:^{ NSLog(@"追加任务2%@",[NSThread currentThread]); }]; // 当 NSBlockOperation中的任务数 > 1 之后, 无论是将操作添加到主线程,还是在主线程直接执行 start ,NSBlockOperation中的任务执行顺序都不确定,执行线程也不确定!
// 一半在开发的时候,要避免向 NSBlockOperation 中追加任务!
// 如果任务都是在子线程中执行,并且不需要保证执行顺序,可以直接追加任务!

5.直接通过操作队列添加任务

// 直接通过操作队列添加任务!

    //将block中的内容当做一个操作添加到主队列中!
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"---------1%@",[NSThread currentThread]); }]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"---------2%@",[NSThread currentThread]); }]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"---------3%@",[NSThread currentThread]); }]; [[[NSOperationQueue alloc] init] addOperationWithBlock:^{ NSLog(@"---------4%@",[NSThread currentThread]); }]; [[[NSOperationQueue alloc] init] addOperationWithBlock:^{ NSLog(@"---------5%@",[NSThread currentThread]); }]; [[[NSOperationQueue alloc] init] addOperationWithBlock:^{ NSLog(@"---------6%@",[NSThread currentThread]); }];

6.给操作添加操作依赖,保证操作的顺序执行,避免循环依赖

// NSOperation 相对于 GCD 来说,增加了以下管理线程的功能:
// 1. NSOperation可以添加操作依赖: 保证操作的执行顺序! --> 和GCD中将任务添加到一个串行队列中是一样的! 一个串行队列会对应一条线程! // GCD 中的按顺序执行(串行队列)----> 串行执行!
// 添加操作依赖之后,系统有可能串行执行保证任务的执行顺序,还有可能采用线程同步技术,保证任务执行顺序! NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"-------222 %@",[NSThread currentThread]); }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"-------333 %@",[NSThread currentThread]); }]; NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"-------444 %@",[NSThread currentThread]); }]; // 四个操作都是耗时操作! 并且要求按顺序执行! 操作2是UI操作! // 添加操作依赖的注意点:
// 1. 不要添加循环依赖!
// 2. 一定要在将操作添加到操作队列中之前添加操作依赖! // 优点: 对于不同操作队列中的操作,操作依赖依然有效! // 添加操作依赖!
[op2 addDependency:op1]; [op3 addDependency:op2]; [op4 addDependency:op3]; // [op2 addDependency:op3];
// [op1 addDependency:op4]; // 将操作添加到操作队列中
NSOperationQueue *quque = [[NSOperationQueue alloc] init]; [quque addOperation:op3];
[quque addOperation:op1];
[quque addOperation:op4]; // 将操作2 添加到主队列中
[[NSOperationQueue mainQueue] addOperation:op2];

7.NSOperation的高级操作,暂停/恢复/取消/设置最大线程数

  // 遇到并发编程,什么时候选择 GCD ,什么时候选择 NSOperation!

// 1.简单的开启线程/回到主线程,选择 GCD : 效率更高,简单!

// 2.需要管理操作(考虑到与用户交互!),使用 NSOperation!

 // NSOperation高级操作:

    // 1. 添加操作依赖!
// 2. 管理操作: 重点! 是操作队列的方法!
// 2.1 暂停/恢复 取消 操作!
// 2.2 开启合适的线程数量!(最多不超过6条!) // 一半开发的时候,会将操作队列设置成一个全局的变量(属性)!
// NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"0----------"); [self test];
}]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ [self test];
}]; [queue addOperation:op]; // 1. 暂停操作// 开始滚动的时候
[queue setSuspended:YES]; // 2. 恢复操作// 滚动结束的时候
[queue setSuspended:NO]; // 3. 取消所有操作// 接收到内存警告
[queue cancelAllOperations]; // 3补充: 取消单个操作!是操作的方法!
[op cancel]; // 设置最大并发数,开启合适的线程数量 // 实例化操作队列的时候
[queue setMaxConcurrentOperationCount:]; // 遇到并发编程,什么时候选择 GCD ,什么时候选择 NSOperation!
// 1.简单的开启线程/回到主线程,选择 GCD : 效率更高,简单!
// 2.需要管理操作(考虑到与用户交互!),使用 NSOperation!

8.block的循环引用问题,使用__weak typeof(self)weakself = self;弱引用

#import "HMViewController.h"

@interface HMViewController ()

// 全局操作队列
@property(nonatomic ,strong)NSOperationQueue *queue; //
@property(nonatomic ,strong)NSMutableArray *array; @end @implementation HMViewController -(NSOperationQueue *)queue
{
if (!_queue) { _queue = [[NSOperationQueue alloc] init]; [_queue setMaxConcurrentOperationCount:];
} return _queue;
} -(NSMutableArray *)array
{
if (!_array) {
_array = [NSMutableArray array];
}
return _array;
} - (void)viewDidLoad {
[super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor];
//
NSLog(@"控制器创建成功!"); } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"touchesBegan");
// block! // 1. 创建操作 // 为了防止 block 中使用 self 出现的循环引用问题! 一般在 block中使用 self 的时候,要使用 self 的弱引用!!! // 为了安全,block中出现self,都使用 弱引用写法! // weakself : 下面就是 self 的弱引用写法!
__weak typeof(self)weakself = self; // __weak HMViewController *wself = self;
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ [self test];
}]; // 将操作添加到 array 中!
[self.array addObject:op]; // self --> queue -->op --> block --> self : 循环引用链条! // 2. 将操作添加到操作队列中
// 因为操作执行完毕之后,操作队列会自动释放其中的操作,所以,在操作中(NSblockOperation)block里有了 self,没有关系,能够释放.不会造成循环引用!
[self.queue addOperation:op]; } -(void)test
{
NSLog(@"------%@",[NSThread currentThread]);
} -(void)dealloc
{
NSLog(@"控制器销毁了!");
}

9.线程间通信,在子线程下载图片,在主线程更新UI

// 1 在子线程下载图片

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

        // 如果图片地址中出现了 & 符号,换一张图片!
// image :下载好的网络图片
UIImage *image = [self downloadWebImageWithUrlString:@"http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg"]; // 回到主线程!
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 显示图片
self.imageView.image = image;
}];
}]; [self.queue addOperation:op]; NSLog(@"touchesEnd"); } // 下载网络图片的方法
- (UIImage *)downloadWebImageWithUrlString:(NSString *)urlString
{
NSURL *url = [NSURL URLWithString:urlString]; // 下载方法!耗时方法!
NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; return image;
}

10.自定义NSOperation,继承NSOperation,重写mian方法

加自动释放池

//
// HMDownloadOperation.h
// 09-线程间通信
//
// Created by HM on 16/1/25.
// Copyright © 2016年 HM. All rights reserved.
// #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> @class HMDownloadOperation; @protocol HMDownloadOperationDelegate <NSObject> -(void)downloadImageWithOperation:(HMDownloadOperation *)operation; @end @interface HMDownloadOperation : NSOperation // 代理属性
@property(nonatomic ,weak) id<HMDownloadOperationDelegate> delegate; // 写一个图片属性// 下载好的图片
@property(nonatomic ,strong) UIImage *image; // 图片下载地址
@property(nonatomic ,copy)NSString *urlString; @end
//
// HMDownloadOperation.m
// 09-线程间通信
//
// Created by HM on 16/1/25.
// Copyright © 2016年 HM. All rights reserved.
// #import "HMDownloadOperation.h" @implementation HMDownloadOperation // 重写 NSOperation 的 main 方法!
// 当把自定义的操作添加到操作队列中,或者直接调用 操作的 start 方法之后,都会自动来执行 main 方法中的内容!
-(void)main
{
// 为了能够及时释放内存,一般会手动书写一个 autoreleasepool!苹果官方文档不要求写!
@autoreleasepool { NSLog(@"----------%@",[NSThread currentThread]); self.image = [self downloadWebImageWithUrlString:self.urlString]; NSLog(@"image:%@",self.image); // 通知/代理/block :为了保证在不同对象之间传值的准确性!采用的是同步传值的方法! // 回到主线程,执行代理方法:
dispatch_async(dispatch_get_main_queue(), ^{
// 执行代理方法
if ([self.delegate respondsToSelector:@selector(downloadImageWithOperation:)]) {
[self.delegate downloadImageWithOperation:self];
}
});
}
} // 下载网络图片的方法
- (UIImage *)downloadWebImageWithUrlString:(NSString *)urlString
{
NSURL *url = [NSURL URLWithString:urlString]; // 下载方法!耗时方法!
NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; return image;
} @end

11.操作完成之后的回调completionBlock

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"--------%@",[NSThread currentThread]);

    }];

    // 操作完成之后的回调!
// op.completionBlock = ^(){
//
// NSLog(@"操作执行完毕!");
//
// };
[op setCompletionBlock:^{ NSLog(@"操作执行完毕!");
}]; [op start];

3.多线程NSOperation的更多相关文章

  1. iOS多线程 NSOperation的用法

    上一篇写了 GCD 的使用,接下来就了解一下 NSOperation ,NSOperation是苹果对 GCD 的 OC 版的一个封装,但是相对于GCD来说可控性更强,并且可以加入操作依赖. NSOp ...

  2. iOS边练边学--多线程NSOperation介绍,子类实现多线程的介绍(任务和队列),队列的取消、暂停(挂起)和恢复,操作依赖与线程间的通信

    一.NSOperation NSOperation和NSOperationQueue实现多线程的具体步骤 先将需要执行的操作封装到一个NSOperation对象中 然后将NSOperation对象添加 ...

  3. iOS多线程--NSOperation 浅显易懂

    NSOperation是基于GCD的一套多线程实现方案,和GCD一样,线程的生命周期是由系统来自动管理的,不用像NSThread和Pthread一样让程序员手动管理.相对于GCD来说,它更加地面向对象 ...

  4. iOS开发:Swift多线程NSOperation的使用

    介绍: NSOperation是基于GCD实现,封装了一些更为简单实用的功能,因为GCD的线程生命周期是自动管理,所以NSOperation也是自动管理.NSOperation配合NSOperatio ...

  5. 多线程NSOperation

      NSOperation(经常使用): 1.为什么会有NSOperation?弥补gcd的一些问题:1)下载为例子:如果gcd放到队列中的block操作面对网络有问题,block之外无法取消bloc ...

  6. iOS多线程--NSOperation

    NSOperation是基于GCD的一套多线程实现方案,和GCD一样,线程的生命周期是由系统来自动管理的,不用像NSThread和Pthread一样让程序员手动管理.相对于GCD来说,它更加地面向对象 ...

  7. iOS之多线程NSOperation

    目前在 iOS 和 OS X 中有两套先进的同步 API 可供我们使用:NSOperation 和 GCD .其中 GCD 是基于 C 的底层的 API ,而 NSOperation 则是 GCD 实 ...

  8. iOS 多线程 NSOperation、NSOperationQueue

    1. NSOperation.NSOperationQueue 简介 NSOperation.NSOperationQueue 是苹果提供给我们的一套多线程解决方案.实际上 NSOperation.N ...

  9. iOS 开发多线程 —— NSOperation

    本文是根据文顶顶老师的博客学习而来,转载地址:http://www.cnblogs.com/wendingding/p/3809042.html 一.NSOperation简介 1.简单说明 NSOp ...

  10. iOS中的多线程 NSOperation

    在ios中,使用多线程有三种方式,分别是:NSThread.NSOperation和NSOperationQueue.GCD,在本节,主要讲解一下NSOperation的使用. NSOperation ...

随机推荐

  1. 普通用户ssh无密码登录设置

    这段时间在做Hadoop的环境配置,用root用户只需要按照一定的步骤进行操作就可以直接实现无密码登录,但如果使用新建用户,怎么尝试都不行. 本帖大部分都是其他人帖子的内容.如果按照下面的步骤还是不能 ...

  2. Python2 下 Unicode 的一个小bug

    关于Python的编码问题已经是老生常谈了,此处主要是介绍一个罕见的问题,也算是Python2的一个bug了(Python3不会有此问题). 在有时候我们去爬取网页或者调用一些第三方库获取文本的时候, ...

  3. Java虚拟机各内存区域的位置及功能的介绍

    Java虚拟机运行时数据区: 相关区域介绍: 程序计数器: 功能:当前线程所执行字节码的行号指示器.若是Java方法记录指令地址,若为Native方法,则不记录 隔离性:线程隔离 Error:无 Ja ...

  4. NeoKylin5.6下安装部署达梦(DM7)数据库

    1.准备操作系统 1.1 系统登录界面 1.2 操作系统版本信息 [root@jdbh ~]# uname -ra Linux jdbh -.el5xen # SMP Fri Jul :: EDT x ...

  5. Learn ZYNC (2)

    AXI HP接口的DMA+GIC编程(参照博客) 参照文档:UG873,博客文档 参考设计代码文件:ug873源码 我的Vivado+SDK工程文件打包(60+M) 我的DMA驱动程序(已完成) Vi ...

  6. MySQL(Percona Server) 5.6 主从复制

    MySQL(Percona Server) 5.6.15 主库:192.168.2.21 从库:192.168.2.22 例如我们同步的数据库为:test. 如果需要同步多个数据库下面会有说明. My ...

  7. Oracle Function

    Oracle Sql 中常用函数 小写字母转大写字母:upper(); 大写字母转小写字母:lower(); 字符串截取函数:substr(str,a,b); a,b为整数,str为字符串, 截取字符 ...

  8. Mac&iOS之多线程--转自http://geeklu.com/2012/02/thread/

    http://geeklu.com/2012/02/thread/ 首先循环体的开始需要检测是否有需要处理的事件,如果有则去处理,如果没有则进入睡眠以节省CPU时间. 所以重点便是这个需要处理的事件, ...

  9. spring <context:component-scan>使用说明(转)

    在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类 ...

  10. Multiprocessor Operating System Design Considerations SYMMETRIC MULTIPROCESSORS

    COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION An SMP operating syst ...