基本概念
1: NSOperation和NSOperationQueue的基本知识点:
NSOperationQueue:代表一个 FIFO 的列队,它负责管理系统提交的多个 NSOperation,NSOperationQueue底层维护一个线性池,会按照顺序启动线程来执行提交给该列队的NSOperation任务.
NSOperation:代表一个多线程任务.NSOperation有NSBlockOperation和NSInvocationOperation两个子类.NSOperation的使用方式有2种:1)自定义NSOperation,实现NSOperation子类.2)直接使用NSBlockOperation或者NSInvocationOperation.
2: 使用NSOperation,NSOperationQueue开发多线程非常简单,只需要2步:
1):创建NSOperationQueue列队,并为该列队设置相应的属性.
2):创建NSOperation子类的对象,并将该对象提交给NSOperationQueue列队,该列队将会按照顺序依次启动每个NSOperation.
3:NSOperationQueue的常用方法和属性
//将NSOperation添加到NSOperationQueue中.
- (void)addOperation:(NSOperation *)op;
//将ops数组中的所有NSOperation添加到NSOperationQueue当中.如果第二个参数设置为 YES,将会阻塞当前线程,直到所有的NSOperation执行完成.如果为 NO, 该方法会立即返回,则ops数组中的所有NSOperation将以异步的方式执行,不会阻塞当前线程.
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
//添加一个block形式的operation
- (void)addOperationWithBlock:(void (^)(void))block;
//只读属性,返回NSOperationQueue中所有的NSOperation
@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
//只读属性,返回NSOperationQueue中管理的NSOperation的数量.
@property (readonly) NSUInteger operationCount ;
//设置,获取列队最大的并发数量
@property NSInteger maxConcurrentOperationCount;
//是否暂停调度正在排队的NSOperation
@property (getter=isSuspended) BOOL suspended;
//NSOperationQueue的名字
@property (nullable, copy) NSString *name ;
NSOperation中新的qualityOfService的属性取代了原来的threadPriority。通过它可以推迟那些不重要的任务,从而让用户体验更加流畅。
NSQualityOfService枚举定义了以下值:
UserInteractive:和图形处理相关的任务,比如滚动和动画。
UserInitiated:用户请求的任务,但是不需要精确到毫秒级。例如,如果用户请求打开电子邮件App来查看邮件。
Utility:周期性的用户请求任务。比如,电子邮件App可能被设置成每五分钟自动检查新邮件。但是在系统资源极度匮乏的时候,将这个周期性的任务推迟几分钟也没有大碍。
Background:后台任务,用户可能并不会察觉对这些任务。比如,电子邮件App对邮件进行引索以方便搜索。
//服务质量
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
@property (nullable, assign ) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0);
//取消所有NSOperationQueue列队中正在排队和执行的NSOperation.
- (void)cancelAllOperations;
//阻塞当前线程,直到所有的NSOperation执行完成
- (void)waitUntilAllOperationsAreFinished;
//该方法返回执行当前的NSOperation的NSOperationQueue列队.
+ (nullable NSOperationQueue *)currentQueue ;
//该方法返回系统主线程的NSOperationQueue列队
+ (NSOperationQueue *)mainQueue ;
NSBlockOperation和NSInvocationOperation的使用
NSBlockOperation和NSInvocationOperation的使用非常相似,区别在于NSInvocationOperation用于将特定的方法封装成为NSOperation,而NSBlockOperation则用于将代码块封装成为NSOperation.
实例:NSBlockOperation和NSInvocationOperation下载图片
#import "ViewController.h"
@interface ViewController (){
NSOperationQueue *queue;
}
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self testOne];
}
-(void)testOne{
queue=[[NSOperationQueue alloc]init];
// 设置该队列最多支持10条并发线程
queue.maxConcurrentOperationCount=10;
}
//使用IB创建界面,添加一个UIImageView和一个UIButton.这里使用NSInvocationOperation.
- (IBAction)downLoadImageButton:(UIButton *)sender {
NSString* url = @"http://g.hiphotos.baidu.com/zhidao/pic/item/
37d3d539b6003af33c9aba42362ac65c1038b6eb.jpg";
//以self的downloadImageFromURL:方法作为执行体,创建NSOperation
NSInvocationOperation* operation = [[NSInvocationOperation alloc]
initWithTarget:self selector:@selector(downloadImageFromURL:)
object:url];
//将NSOperation添加给NSOperationQueue
[queue addOperation:operation];
}
// 定义一个方法作为线程执行体。
-(void)downloadImageFromURL:(NSString *) url
{
// 从网络获取数据
NSData *data = [[NSData alloc]
initWithContentsOfURL:[NSURL URLWithString:url]];
// 将网络数据初始化为UIImage对象
UIImage *image = [[UIImage alloc]initWithData:data];
if(image != nil)
{
// 在主线程中执行updateUI:方法
[self performSelectorOnMainThread:@selector(updateUI:)
withObject:image waitUntilDone:YES];
}
else
{
NSLog(@"---下载图片出现错误---");
}
}
-(void)updateUI:(UIImage*) image
{
self.imageView.image = image;
}
NSBlockOperation的使用,只要替换点击事件中的代码即可.
- (IBAction)downLoadImageButton:(UIButton *)sender {
NSString* url = @"http://g.hiphotos.baidu.com/zhidao/pic/item/
37d3d539b6003af33c9aba42362ac65c1038b6eb.jpg";
// 以传入的代码块作为执行体,创建NSOperation
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{
// 从网络获取数据
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
// 将网络数据初始化为UIImage对象
UIImage *image = [[UIImage alloc]initWithData:data];
if(image != nil)
{
// 在主线程中执行updateUI:方法
[self performSelectorOnMainThread:@selector(updateUI:)
withObject:image waitUntilDone:YES];
}else
{
NSLog(@"---下载图片出现错误---");
}
}];
// 将NSOperation添加给NSOperationQueue
[queue addOperation:operation];
}
效果图:
自定义NSOperation的子类
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface SHOperation : NSOperation
@property (nonatomic , strong) NSURL* url;
@property (nonatomic , strong) UIImageView* imageView;
- (id)initWithURL:(NSURL*)url imageView:(UIImageView*)imageView;
@end
#import "SHOperation.h"
@implementation SHOperation
- (id)initWithURL:(NSURL*)url imageView:(UIImageView*)iv
{
self = [super init];
if (self) {
_imageView = iv;
_url = url;
}
return self;
}
//重写main方法,该方法将作为线程执行体也就是该线程需要完成的任务.
- (void)main
{
//从网络获取数据,将网络数据初始化为UIImage对象
NSData *data = [[NSData alloc]
initWithContentsOfURL:self.url];
UIImage *image = [[UIImage alloc]initWithData:data];
if(image != nil)
{
//因为 main方法代码将会在新线程中执行,所以需要在主线程中执行updateUI:方法
[self performSelectorOnMainThread:@selector(updateUI:)
withObject:image waitUntilDone:YES]; // ①
}
else
{
NSLog(@"---下载图片出现错误---");
}
}
-(void)updateUI:(UIImage*) image
{
self.imageView.image = image;
}
@end
ViewController.m文件中
- (IBAction)downLoadImageButton:(UIButton *)sender {
[self testTwo];
}
//NSOperation一般不会直接使用,而是创建子类,创建子类需要重写一个方法:-(void)main,该方法体将作为NSOperationQueue完成的任务.例子实现效果跟前面一样.
-(void)testTwo{
queue=[[NSOperationQueue alloc]init];
// 设置该队列最多支持10条并发线程
queue.maxConcurrentOperationCount=10;
// 定义要加载的图片的URL
NSURL* url = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/zhidao/pic/item/37d3d539b6003af33c9aba42362ac65c1038b6eb.jpg"];
// 创建SHOperation对象.这里传入了需要的 url,以及下载成功后显示的imageView.
SHOperation * operation = [[SHOperation alloc] initWithURL:url imageView:self.imageView];
// 将NSOperation的子类的实例提交给NSOperationQueue
[queue addOperation:operation];
}
推荐:
http://www.cnblogs.com/kenshincui/p/3983982.html#NSOperation
http://blog.leichunfeng.com/blog/2015/07/29/ios-concurrency-programming-operation-queues/