NSOperation
使用
1.
简介
重点
:
理解操作
NSOperation
和操作队列
NSOperationQueue!
{
1. NSOperation( 操作 ) 简介 :
NSOperation: // 本质是对 GCD 的封装 , OC 语言 .
NSOperation 和 GCD 的比较 :
GCD 使用场合 :
一些简单的需求 , 简单的多线程操作 . // 简单高效
NSOperation 使用场合 :
各个操作之间有依赖关系 , 操作需要取消 / 暂停 ; 需要限制同时执行的线程数量 , 让线程在某时刻停止 / 继续等 .
配合使用 NSOperation 和 NSOperationQueue 也可以实现多线程 .
总结:
从 " 开启 " 线程的角度考虑 : 使用 GCD;
从 " 管理 " 线程的角度考虑 : 使用 NSOperation;
2. NSOperation 使用 :
NSOperation: 抽象类 , 不能直接使用 , 需要使用其子类 .
抽象类 : 定义子类共有的属性和方法 . // CAAnimation/CAPropertyAnimation...
两个常用子类 : NSInvocationOperation( 调用 ) 和 NSBlockOperation( 块 );
两者没有本质区别 , 后者使用 Block 的形式组织代码 , 使用相对方便 .
自定义子类继承自 NSOperation, 实现内部相应的方法 . // 高级用法
}
/*---------------------------- NSOperation 使用 2.NSOperation ------------------------------*/
重点 : 1. NSBlockOperation, NSInvocationOperation 的简单使用 .
{
1. 创建 NSInvocationOperation 对象
// 创建 NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget: self selector: @selector (longTimeOperation:) object: @"op1" ];
// 默认情况下 , 调用 start 方法之后 , 不会开启新线程 , 只会在当前线程执行操作 .
[op1 start];
注意 : 只有将 NSOperation 放到一个 NSOperationQueue 中 , 才会异步执行操作 .
2. 创建 NSBlockOperation 对象
// 创建 NSBlockOperation
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog( @" 下载图片 1---%@" ,[NSThread currentThread]);
}];
// 添加更多操作
[op2 addExecutionBlock:^{
NSLog( @" 下载图片 2---%@" ,[NSThread currentThread]);
}];
[op2 addExecutionBlock:^{
NSLog( @" 下载图片 3---%@" ,[NSThread currentThread]);
}];
// 只要 NSBlockOperation 中封装的操作数 > 1, 调用 start 方法之后就会开启多条线程并发执行
// 如果 NSBlockOperation 中封装的操作数 == 1, 调用 start 方法之后 , 不会开启新线程 , 只会在当前线程执行操作
[op2 start];
注意 : 只要 NSBlockOperation 中封装的操作数 > 1 , 就会异步执行这些操作 .( 将操作添加到 NSOperationQueue 中或者直接调用 start 方法都会开启多条线程异步执行 ).
}
/*---------------------------- NSOperation 使用 3.NSOperationQueue --------------------------*/
重点 : 将操作添加到队列中 ;
{
NSOperation 可以调用 start 方法来执行任务 , 但默认是同步执行的 .
将 NSOperation 添加到 NSOperationQueue( 操作队列 ) 中 , 系统会自动异步执行 NSOperationQueue 中的操作 .
1. NSOperationQueue( 操作队列 ):
主队列 : 主队列中的操作都自动在主线程执行 !
非主队列 : 非主队列中的操作都自动在子线程执行 !
< 1 > 主队列
[NSOperationQueue mainQueue] // 获取主队列
添加到 " 主队列 " 中的操作 , 都会放在主线程执行 !
< 2 > 非主队列
[[NSOperationQueue alloc] init]; // 创建非主队列
添加到 " 非主队列 " 中得操作 , 都会放在子线程中执行 .
2. 使用 : 添加操作到操作队列中 .
// 创建 NSInvocationOperation 操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget: self selector: @selector (longTimeOperation:) object: @"op1" ];
// 创建 NSBlockOperation 操作
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog( @" 下载图片 1---%@" ,[NSThread currentThread]);
}];
// 1. 创建一个 NSOperationQueue
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2. 将操作添加到队列中 .
[queue addOperation:op1];
[queue addOperation:op2];
注意 : 另外一种添加操作到队列中的方法 : block
[queue addOperationWithBlock:^{
NSLog( @" 下载图片 5---%@" ,[NSThread currentThread]);
}];
推荐使用 : block // 简单 . 自己哪个使用熟练就用哪个 .
注意 : 队列中任务的执行是无序的 .
}
/*-------------------------------- NSOperation 使用 4. 常见用法 1 -------------------------------*/
重点 : 1. 设置操作依赖 . 2. 设置最大并发数 .
{
问题 : 是否可以让队列中的操作有序执行 ?
回答上问题 : 能 , 设置操作依赖 .
1. NSOperation 设置操作依赖 : // 执行顺序 : op1,op2,op3;
// 操作 op3 依赖于操作 op2;
[op3 addDependency:op2];
// 操作 op2 依赖于操作 op1;
[op2 addDependency:op1];
注意 : 不能相互依赖 .
2. NSOperationQueue 设置最大并发数 .
并发数 : 同时开启的线程数 .
// 创建操作队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置操作队列的最大并发数
queue.maxConcurrentOperationCount = 3 ;
[queue setMaxConcurrentOperationCount: 3 ];
}
/*-------------------------------- NSOperation 使用 5. 常见用法 2 -------------------------------*/
重点 : 1. 队列的取消 / 暂停 / 恢复 2. 线程间通信 . 注意问题 : 为毛要取消 / 恢复队列 ? 在什么时候用 ?
{
1. NSOperationQueue 的取消 / 暂停 / 恢复
// 取消操作 op1. 取消单个操作 .
[op1 cancel];
// 取消所有操作 , 不会再次恢复
[queue cancelAllOperations];
// 暂停所有操作 ; 注意 , 已经开始的操作不会暂停 .
[queue setSuspended: YES ];
// 重新开始所有操作
[queue setSuspended: NO ];
问 : 为毛要取消恢复队列 ? 在什么时候用 ?
答 : 1. 为了内存管理 , 处理内存警告 ; 2. 为了用户体验 , 保证滚动流畅 .
// 接收到内存警告的时候果断取消队列中的所有操作
- ( void )didReceiveMemoryWarning
{
[ super didReceiveMemoryWarning];
[queue cancelAllOperations]; // 取消队列中的所有任务(不可恢复)
}
// 开始滚动的时候暂停队列中的任务 .
- ( void )scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[queue setSuspended: YES ]; // 暂停队列中的所有任务
}
// 滚动结束的时候恢复队列中的任务 .
- ( void )scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:( BOOL )decelerate
{
[queue setSuspended: NO ]; // 恢复队列中的所有任务
}
2. 线程间通信 // 子线程下载图片 , 主线程设置图片 .
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1. 异步下载图片
NSURL *url = [NSURL URLWithString: @"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg" ];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 2. 回到主线程,显示图片
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self .imageView.image = image;
}];
}];
}
{
1. NSOperation( 操作 ) 简介 :
NSOperation: // 本质是对 GCD 的封装 , OC 语言 .
NSOperation 和 GCD 的比较 :
GCD 使用场合 :
一些简单的需求 , 简单的多线程操作 . // 简单高效
NSOperation 使用场合 :
各个操作之间有依赖关系 , 操作需要取消 / 暂停 ; 需要限制同时执行的线程数量 , 让线程在某时刻停止 / 继续等 .
配合使用 NSOperation 和 NSOperationQueue 也可以实现多线程 .
总结:
从 " 开启 " 线程的角度考虑 : 使用 GCD;
从 " 管理 " 线程的角度考虑 : 使用 NSOperation;
2. NSOperation 使用 :
NSOperation: 抽象类 , 不能直接使用 , 需要使用其子类 .
抽象类 : 定义子类共有的属性和方法 . // CAAnimation/CAPropertyAnimation...
两个常用子类 : NSInvocationOperation( 调用 ) 和 NSBlockOperation( 块 );
两者没有本质区别 , 后者使用 Block 的形式组织代码 , 使用相对方便 .
自定义子类继承自 NSOperation, 实现内部相应的方法 . // 高级用法
}
/*---------------------------- NSOperation 使用 2.NSOperation ------------------------------*/
重点 : 1. NSBlockOperation, NSInvocationOperation 的简单使用 .
{
1. 创建 NSInvocationOperation 对象
// 创建 NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget: self selector: @selector (longTimeOperation:) object: @"op1" ];
// 默认情况下 , 调用 start 方法之后 , 不会开启新线程 , 只会在当前线程执行操作 .
[op1 start];
注意 : 只有将 NSOperation 放到一个 NSOperationQueue 中 , 才会异步执行操作 .
2. 创建 NSBlockOperation 对象
// 创建 NSBlockOperation
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog( @" 下载图片 1---%@" ,[NSThread currentThread]);
}];
// 添加更多操作
[op2 addExecutionBlock:^{
NSLog( @" 下载图片 2---%@" ,[NSThread currentThread]);
}];
[op2 addExecutionBlock:^{
NSLog( @" 下载图片 3---%@" ,[NSThread currentThread]);
}];
// 只要 NSBlockOperation 中封装的操作数 > 1, 调用 start 方法之后就会开启多条线程并发执行
// 如果 NSBlockOperation 中封装的操作数 == 1, 调用 start 方法之后 , 不会开启新线程 , 只会在当前线程执行操作
[op2 start];
注意 : 只要 NSBlockOperation 中封装的操作数 > 1 , 就会异步执行这些操作 .( 将操作添加到 NSOperationQueue 中或者直接调用 start 方法都会开启多条线程异步执行 ).
}
/*---------------------------- NSOperation 使用 3.NSOperationQueue --------------------------*/
重点 : 将操作添加到队列中 ;
{
NSOperation 可以调用 start 方法来执行任务 , 但默认是同步执行的 .
将 NSOperation 添加到 NSOperationQueue( 操作队列 ) 中 , 系统会自动异步执行 NSOperationQueue 中的操作 .
1. NSOperationQueue( 操作队列 ):
主队列 : 主队列中的操作都自动在主线程执行 !
非主队列 : 非主队列中的操作都自动在子线程执行 !
< 1 > 主队列
[NSOperationQueue mainQueue] // 获取主队列
添加到 " 主队列 " 中的操作 , 都会放在主线程执行 !
< 2 > 非主队列
[[NSOperationQueue alloc] init]; // 创建非主队列
添加到 " 非主队列 " 中得操作 , 都会放在子线程中执行 .
2. 使用 : 添加操作到操作队列中 .
// 创建 NSInvocationOperation 操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget: self selector: @selector (longTimeOperation:) object: @"op1" ];
// 创建 NSBlockOperation 操作
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog( @" 下载图片 1---%@" ,[NSThread currentThread]);
}];
// 1. 创建一个 NSOperationQueue
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 2. 将操作添加到队列中 .
[queue addOperation:op1];
[queue addOperation:op2];
注意 : 另外一种添加操作到队列中的方法 : block
[queue addOperationWithBlock:^{
NSLog( @" 下载图片 5---%@" ,[NSThread currentThread]);
}];
推荐使用 : block // 简单 . 自己哪个使用熟练就用哪个 .
注意 : 队列中任务的执行是无序的 .
}
/*-------------------------------- NSOperation 使用 4. 常见用法 1 -------------------------------*/
重点 : 1. 设置操作依赖 . 2. 设置最大并发数 .
{
问题 : 是否可以让队列中的操作有序执行 ?
回答上问题 : 能 , 设置操作依赖 .
1. NSOperation 设置操作依赖 : // 执行顺序 : op1,op2,op3;
// 操作 op3 依赖于操作 op2;
[op3 addDependency:op2];
// 操作 op2 依赖于操作 op1;
[op2 addDependency:op1];
注意 : 不能相互依赖 .
2. NSOperationQueue 设置最大并发数 .
并发数 : 同时开启的线程数 .
// 创建操作队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置操作队列的最大并发数
queue.maxConcurrentOperationCount = 3 ;
[queue setMaxConcurrentOperationCount: 3 ];
}
/*-------------------------------- NSOperation 使用 5. 常见用法 2 -------------------------------*/
重点 : 1. 队列的取消 / 暂停 / 恢复 2. 线程间通信 . 注意问题 : 为毛要取消 / 恢复队列 ? 在什么时候用 ?
{
1. NSOperationQueue 的取消 / 暂停 / 恢复
// 取消操作 op1. 取消单个操作 .
[op1 cancel];
// 取消所有操作 , 不会再次恢复
[queue cancelAllOperations];
// 暂停所有操作 ; 注意 , 已经开始的操作不会暂停 .
[queue setSuspended: YES ];
// 重新开始所有操作
[queue setSuspended: NO ];
问 : 为毛要取消恢复队列 ? 在什么时候用 ?
答 : 1. 为了内存管理 , 处理内存警告 ; 2. 为了用户体验 , 保证滚动流畅 .
// 接收到内存警告的时候果断取消队列中的所有操作
- ( void )didReceiveMemoryWarning
{
[ super didReceiveMemoryWarning];
[queue cancelAllOperations]; // 取消队列中的所有任务(不可恢复)
}
// 开始滚动的时候暂停队列中的任务 .
- ( void )scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[queue setSuspended: YES ]; // 暂停队列中的所有任务
}
// 滚动结束的时候恢复队列中的任务 .
- ( void )scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:( BOOL )decelerate
{
[queue setSuspended: NO ]; // 恢复队列中的所有任务
}
2. 线程间通信 // 子线程下载图片 , 主线程设置图片 .
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1. 异步下载图片
NSURL *url = [NSURL URLWithString: @"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg" ];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 2. 回到主线程,显示图片
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self .imageView.image = image;
}];
}];
}