苹果文档:
删除指定的依赖关系
NSOperation 是另一个”并发技术”,程序员不需要关心,,并发技术 不是多线程
NSOperation
- 核心概念:把操作(异步)添加到队列(全局的并发队列)!
- 主队列 mainQueue
- OC的框架 更加面向对象
- 是对 GCD 的封装
- iOS 2.0 推出的,苹果在推出GCD之后,对NSOperation的底成全部重写了.
- 高级功能:
- 最大操作并发数(GCD不好做)
-在iOS 7.0 之前 使用GCD & NSOperation 能够开启的线程不多,5-6条
- 从iOS 8.0 开始,能够开很多个线程,如果不控制,会造成资源浪费
- 继续/暂停/全部取消
- 依赖关系(CGD,同步认为是来制定依赖关系!)
GCD:
- 将”任务(block)”添加到队列(串行/并发/主队列),并且指定执行的函数(同步/异步)
- C 语言的框架 dispatch_xxx 函数
- iOS 4.0 推出的,针对多核处理器的并发技术
- iOS 4.0 推出的,针对多核处理器的并发技术
-高级功能:
- 一次性 once
- 延迟操作 after
- 调度组 (op可以做,但是太复杂)
The NSOperation class is an abstract class you use to encapsulate the code and data associated with a single task.
- NSOperation 类是一个"抽象类",封装与一个任务关联的代码和数据
- NSOperation 类是一个"抽象类",封装与一个任务关联的代码和数据
- 抽象类不能直接使用,需要使用子类
NSOperation
子类:
* NSBlockOperation (块)
* NSInvocationOperation(调度.用得少)
- 队列 NSOperationQueue
目前学过的抽象类
1. UIGestureRecognizer
2. CAAnimation
3. CAPropertyAnimation(属性动画)
- CABasicAnimation(基本动画,fromValue, toValue)
- CAKeyframeAnimation(values,path)
2. CAAnimation
3. CAPropertyAnimation(属性动画)
- CABasicAnimation(基本动画,fromValue, toValue)
- CAKeyframeAnimation(values,path)
- 通过修改图层的可动画属性
// MARK: - NSBlockOperation
// block operation 将代码都写在一起,便于维护
// MARK: - 更简单的
// 只要是 NSOpeartion 的子类,都可以直接添加到队列!
// MARK: - 线程间通讯
- (void)opDemo5 {
[self.queue addOperationWithBlock:^{
NSLog(@"耗时的操作 %@", [NSThread currentThread]);
// 在主线程更新 UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"更新 UI %@", [NSThread currentThread]);
}];
}];
- (void)opDemo5 {
[self.queue addOperationWithBlock:^{
NSLog(@"耗时的操作 %@", [NSThread currentThread]);
// 在主线程更新 UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"更新 UI %@", [NSThread currentThread]);
}];
}];
}
- (void)opDemo4 {
// 通常在应用程序中,会用一个属性来记录 队列,全局管理所有的异步操作
// NSOperationQueue *q = [[NSOperationQueue alloc] init];
// 直接向队列添加 block 操作
for (int i = 0; i < 10; ++i) {
[self.queue addOperationWithBlock:^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
}];
}
// 向队列添加 NSBlockOperation
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"BLOCK --- %@ - %d", [NSThread currentThread], 100);
}];
[self.queue addOperation:op1];
// invocation op
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"invocation"];
[self.queue addOperation:op2];
// 通常在应用程序中,会用一个属性来记录 队列,全局管理所有的异步操作
// NSOperationQueue *q = [[NSOperationQueue alloc] init];
// 直接向队列添加 block 操作
for (int i = 0; i < 10; ++i) {
[self.queue addOperationWithBlock:^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
}];
}
// 向队列添加 NSBlockOperation
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"BLOCK --- %@ - %d", [NSThread currentThread], 100);
}];
[self.queue addOperation:op1];
// invocation op
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"invocation"];
[self.queue addOperation:op2];
}
- (void)opDemo3 {
NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i = 0; i < 10; ++i) {
// 操作
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
}];
// 将操作添加到队列
[q addOperation:op];
}
NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i = 0; i < 10; ++i) {
// 操作
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@ - %d", [NSThread currentThread], i);
}];
// 将操作添加到队列
[q addOperation:op];
}
}
NSOpeartion 是对 GCD 的封装,是 OC 的!比 GCD 的使用简单
队列:全局队列(并发队列)
操作:异步执行的任务
*/
- (void)opDemo2 {
NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i = 0; i < 10; ++i) {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@(i)];
[q addOperation:op];
}
队列:全局队列(并发队列)
操作:异步执行的任务
*/
- (void)opDemo2 {
NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i = 0; i < 10; ++i) {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@(i)];
[q addOperation:op];
}
}
- (void)opDemo1 {
// Invocation: 调度,调用
// 提示:NSInvocation 是一个非常古老的技术,暂时不建议大家学习和探索!
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"Invocation"];
// 启动操作,会在当前线程执行 @selector 方法
// [op start];
// 将操作添加到队列 -> 异步执行 @selector 方法
NSOperationQueue *q = [[NSOperationQueue alloc] init];
// Invocation: 调度,调用
// 提示:NSInvocation 是一个非常古老的技术,暂时不建议大家学习和探索!
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"Invocation"];
// 启动操作,会在当前线程执行 @selector 方法
// [op start];
// 将操作添加到队列 -> 异步执行 @selector 方法
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperation:op];
}
- (void)downloadImage:(id)obj {
NSLog(@"%@ - %@", [NSThread currentThread], obj);
NSLog(@"%@ - %@", [NSThread currentThread], obj);
}
七. 最大并发数操作数
- (void)opDemo1 {
// 设置队列的最大并发操作数(队列是负责调度任务的)
self.queue.maxConcurrentOperationCount = 2;
NSLog(@"start");
for (int i = 0; i < 20; ++i) {
[self.queue addOperationWithBlock:^{
// 休眠 - 效果? 1秒钟之后,全部打印
[self.queue addOperationWithBlock:^{
// 休眠 - 效果? 1秒钟之后,全部打印
[NSThread sleepForTimeInterval:1.0];
NSLog(@"%@ - %d", [NSThread currentThread], i);
}];
}
}];
}
}
八.暂停/继续
- (IBAction)pauseAndResume {
// 判断队列中是否有操作,只有包含操作的时候,才继续后续操作
if (self.queue.operationCount == 0) {
NSLog(@"没有操作");
return;
}
// 一旦设置了对列的挂起,再继续添加操作,操作都不会执行
self.queue.suspended = !self.queue.isSuspended;
if (self.queue.isSuspended) {
// 如果队列被挂起,operationCount 中是包含没有执行完的操作数量
NSLog(@"暂停了 %tu", self.queue.operationCount);
} else {
// 包含队列中所有要调度的操作
NSLog(@"继续 %tu", self.queue.operationCount);
}
// 判断队列中是否有操作,只有包含操作的时候,才继续后续操作
if (self.queue.operationCount == 0) {
NSLog(@"没有操作");
return;
}
// 一旦设置了对列的挂起,再继续添加操作,操作都不会执行
self.queue.suspended = !self.queue.isSuspended;
if (self.queue.isSuspended) {
// 如果队列被挂起,operationCount 中是包含没有执行完的操作数量
NSLog(@"暂停了 %tu", self.queue.operationCount);
} else {
// 包含队列中所有要调度的操作
NSLog(@"继续 %tu", self.queue.operationCount);
}
}
// MARK: 取消所有操作
// 案例:下载小电影,下载完第一个就后悔了,取消所有下载操作
- (IBAction)cancelAll {
// 给队列发送取消操作的消息!
[self.queue cancelAllOperations];
// 直觉上会以为:cancelAllOperations 一调用,队列中就没有操作了!
// 结果:cancelAllOperations 方法是通知队列取消其中的操作,在队列取消完成之前,操作计数并不会发生变化!
// 包含正在执行中的操作+还没有调度的操作
NSLog(@"操作数量:%tu", self.queue.operationCount);
// 案例:下载小电影,下载完第一个就后悔了,取消所有下载操作
- (IBAction)cancelAll {
// 给队列发送取消操作的消息!
[self.queue cancelAllOperations];
// 直觉上会以为:cancelAllOperations 一调用,队列中就没有操作了!
// 结果:cancelAllOperations 方法是通知队列取消其中的操作,在队列取消完成之前,操作计数并不会发生变化!
// 包含正在执行中的操作+还没有调度的操作
NSLog(@"操作数量:%tu", self.queue.operationCount);
}
依赖关系
// MARK: 依赖关系
// 举个栗子:用户登录,付费,下载,通知用户
- (void)dependency {
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"用户登录 %@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"付费 %@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0f];
NSLog(@"下载 %@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"更新UI %@", [NSThread currentThread]);
// 举个栗子:用户登录,付费,下载,通知用户
- (void)dependency {
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"用户登录 %@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"付费 %@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0f];
NSLog(@"下载 %@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"更新UI %@", [NSThread currentThread]);
}];
// 注意:在指定依赖关系时,注意不要出现循环依赖
// 另外:关于死不死,在不同iOS 版本上不同,不同的 MAC 版本上表现都不一样
// 用户登录之前,先更新 UI
[op1 addDependency:op4];
// waitUntilFinished == NO,异步的 YES 是同步的
[self.queue addOperations:@[op1, op2, op3] waitUntilFinished:NO];
// 更新UI的操作,应该由主队列来调度
[[NSOperationQueue mainQueue] addOperation:op4];
NSLog(@"come here");