NSOperation(操作) 是一个抽象类 不能直接使用;
NSOperation 有两个直接子类;NSInvocationOperation(调用)和NSBlockOperation(代码块)
NSOperation是对GCD的进一步封装,相比于GCD而言,GCD使用方便,适用于简单的线程操作,不能控制
NSOperation是可以控制的各个操作之间有依赖关系,可以 - (void)start; - (void)cancel;
添加/移除操作依赖
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
操作必定执行main方法
- (void)main;
实例代码:
- (void)viewDidLoad {
[super viewDidLoad];
// NSOperation本质是对GCD的封装
// NSOperation
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testLongs) object:nil];
// 默认情况下调用start方法之后不会开启新的线程,只会在当前线程中执行操作
[operation1 start];
// 只有将操作放入到操作队列中(NSOperationQueue)中,才会异步执行操作
}
- (void)testLongs {
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/new/images/angle00.png"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"%@",[NSThread currentThread]);
self.imageIcon1.image = image;
}
- (UIImageView *)imageIcon1{
if (_imageIcon1 == nil) {
_imageIcon1 = [[UIImageView alloc] initWithFrame: CGRectMake(20, 20, 200, 200)];
[self.view addSubview:_imageIcon1];
}
return _imageIcon1;
}
// 只有将操作放入到操作队列中(NSOperationQueue)中,才会异步执行操作
[[NSBlockOperation blockOperationWithBlock:^{
NSData *data = [NSData dataWithContentsOfURL:self.url];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"%@",[NSThread currentThread]);
self.imageIcon2.image = image;
}] start];
NSBlockOperation 实例:
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
NSData *data = [NSData dataWithContentsOfURL:self.url];
UIImage *image = [UIImage imageWithData:data];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.imageIcon1.image = image;
});
}];
// 添加多个操作
[blockOperation addExecutionBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
NSData *data = [NSData dataWithContentsOfURL:self.url];
UIImage *image = [UIImage imageWithData:data];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.imageIcon2.image = image;
});
}];
[blockOperation addExecutionBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
NSData *data = [NSData dataWithContentsOfURL:self.url];
UIImage *image = [UIImage imageWithData:data];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.imageIcon3.image = image;
});
}];
// 只要NSBlockOperation中封装的操作数 > 1 调用star方法后,会开启多条线程
多个任务是同时执行的
// 只要NSBlockOperation中封装的操作数 == 1 时 调用start方法后不会开启新线程(只在主线程中执行操作)
[blockOperation start];
*操作队列:(NSOperationQueue)
实例代码:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
// 创建操作
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1---%@",[NSThread currentThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.imageIcon1.image = [self imageWithURL:self.url];
});
}];
[blockOp addExecutionBlock:^{
NSLog(@"2---%@",[NSThread currentThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.imageIcon2.image = [self imageWithURL:self.url];
});
}];
[blockOp addExecutionBlock:^{
NSLog(@"3---%@",[NSThread currentThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.imageIcon3.image = [self imageWithURL:self.url];
});
}];
[blockOp addExecutionBlock:^{
NSLog(@"4---%@",[NSThread currentThread]);
// [self imageWithURL:self.url];
}];
[self.myQueue addOperation:blockOp];
//-------------该操作封装的任务是异步执行的,
/*
NSOperation[1664:217071] 4---<NSThread: 0x7fe2b3c65430>{number = 5, name = (null)}
NSOperation[1664:217072] 2---<NSThread: 0x7fe2b3c65020>{number = 3, name = (null)}
NSOperation[1664:217074] 1---<NSThread: 0x7fe2b3e10130>{number = 2, name = (null)}
NSOperation[1664:217073] 3---<NSThread: 0x7fe2b3e0a7d0>{number = 4, name = (null)}
NSOperation[1664:217072] 操作完成后的回调代码,,鸡肋
*/
blockOp.completionBlock = ^{
NSLog(@"操作完成后的回调代码,,鸡肋");
};
}
- (UIImage *)imageWithURL:(NSURL *)url{
NSData *data = [NSData dataWithContentsOfURL:url];
return [UIImage imageWithData:data];
}
/**
* 创建一个队列 通过getter方法获取
*/
- (NSOperationQueue *)myQueue{
if (_myQueue == nil) {
_myQueue = [[NSOperationQueue alloc] init];
}
return _myQueue;
}
- (UIImageView *)imageIcon1{
if (_imageIcon1 == nil) {
_imageIcon1 = [[UIImageView alloc] initWithFrame: CGRectMake(20, 20, 200, 200)];
[self.view addSubview:_imageIcon1];
}
return _imageIcon1;
}
- (UIImageView *)imageIcon2{
if (_imageIcon2 == nil) {
_imageIcon2 = [[UIImageView alloc] initWithFrame: CGRectMake(20, 200, 200, 200)];
[self.view addSubview:_imageIcon2];
}
return _imageIcon2;
}
- (NSURL *)url{
if (_url == nil) {
NSString *str = @"http://127.0.0.1/new/images/angle00.png";
_url = [NSURL URLWithString:str];
}
return _url;
}
- (UIImageView *)imageIcon3{
if (_imageIcon3 == nil) {
_imageIcon3= [[UIImageView alloc] initWithFrame: CGRectMake(20, 400, 200, 200)];
[self.view addSubview:_imageIcon3];
}
return _imageIcon3;
}
*操作的执行顺序是不确定的:
如果要限制操作的执行顺序,可以添加操作依赖
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
__weak typeof(self) wself = self;
NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{
UIImage *image = [self imageWithURL:self.url];
dispatch_async(dispatch_get_main_queue(), ^{
wself.imageIcon1.image = image;
});
}];
NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{
UIImage *image = [self imageWithURL:self.url];
dispatch_async(dispatch_get_main_queue(), ^{
wself.imageIcon2.image = image;
});
}];
NSBlockOperation *blockOp3 = [NSBlockOperation blockOperationWithBlock:^{
UIImage *image = [self imageWithURL:self.url];
dispatch_async(dispatch_get_main_queue(), ^{
wself.imageIcon3.image = image;
});
}];
// blockOp2的执行依赖于blockOp1 (blockOp1执行完后才会执行blockOp2)
[blockOp2 addDependency:blockOp1];
[blockOp3 addDependency:blockOp2];
[self.myQueue addOperation:blockOp1];
[self.myQueue addOperation:blockOp2];
[[NSOperationQueue mainQueue] addOperation:blockOp3];
//----------------
// 添加操作依赖注意事项
/**
* 1> 需要将操作依赖放在添加操作到队列之前,不然不起丝毫作用
*
* 2> 不要循环添加依赖,后果自负
*
* 3> 添加到不同队列中的操作,操作依然有效
*
* 4> 向队列中添加操作的顺序和操作依赖没有丝毫关系
*
* 5> 如果需要对操作做依赖,必须将任务封装在操作中,NSOperation中的操作从某种意义上代替的GCD中的串行队列,
* 但是GCD效率更高,不过NSoperation是可以控制的
*/
}
*操作队列:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
}];
// 操作队列
// 创建一个非主队列,
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发数量
[queue setMaxConcurrentOperationCount:6];
// queue.maxConcurrentOperationCount = 4;
// 将操作添加到队列中
[queue addOperation:blockOperation];
// 取消所有操作 当收到内存警告的时候可以取消所的操作, 取消操作后不会恢复
[queue cancelAllOperations];
// 取消单个操作
[blockOperation cancel];
// 暂停/继续所有操作
[queue setSuspended:YES];
// queue.suspended = YES;
queue.suspended = NO;
/**
* 为什么要取消操作,什么情况下要取消操作
*
* 1> 为了用户,为了用户体验,保证程序的流畅
*
* 2> 为了管理内存,方式系统在低内存情况下杀死app
*/
}
// 接收到内存警告的时候果断取消队列中的所有操作
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// [queue cancelAllOperations]; // 取消队列中的所有任务(不可恢复)
}
// 开始滚动的时候暂停队列中的任务.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// [queue setSuspended:YES]; // 暂停队列中的所有任务
}
// 滚动结束的时候恢复队列中的任务.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
// [queue setSuspended:NO]; // 恢复队列中的所有任务
}
*线程间通信:
0> 子线程下载图片(数据),主线程更新UI
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// __weak typeof(self) weakSelf = self;
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
// UIImage *image = [self imageWithURL:self.url];
NSData *data = [NSData dataWithContentsOfURL:self.url];
UIImage *image = [UIImage imageWithData:data];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageIcon1.image = image;
}];
}];
[queue addOperation:blockOp];
}