NSOperation&&NSOperationQueue使用
NSOperation
用来封装我们想要异步执行的任务(下载图片/图片滤镜操作), NSOperation 是一个抽象类,与 NSNumber 是一样,本身并没有多少的用途,不能向 NSOperationQueue 中添加操作。有用的是它的子类
NSInvocationOperation
继承自 NSOperation 的子类,能将一个方法成封装任务,并提交给NSOperationQueue 调度
同步执行
1 NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"invocation"]; 2 [invocationOperation start];在这里创建了一个 NSInvocationOperation 对象, NSInvocationOperation 将一个方法(doSomething:)添加到操作中,然后我们直接调用了 start 方法,调用这个方法后,doSomething: 方法中的任务会在当前线程中同步执行
异步执行
1 NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"invocation"]; 2 3 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 4 5 [queue addOperation:invocationOperation];同样创建了一个 NSInvocationOperation 对象, NSInvocationOperation 将一个方法(doSomething:)添加到操作中,在方法中做我们想要异步的任务,然后再交给队列去调度,会在子线程中执行 (object参数是给doSomething:传递参数)
NSBlockOperation
同样是继承自 NSOperation 的子类,能将多个 block 添加到操作中,提交给 NSOperationQueue 调度
同步执行
1 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 2 3 // 任务A 4 5 }]; 6 7 [blockOperation start];用类方法创建一个 NSBlockOperation 对象,并向操作中添加任务,调用 start 方法,在当前线程同步执行
异步执行
1 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 2 3 // 任务A 4 5 }]; 6 7 [blockOperation addExecutionBlock:^{ 8 9 // 任务B 10 11 }]; 12 13 [blockOperation addExecutionBlock:^{ 14 15 // 任务C 16 17 }]; 18 19 [blockOperation start];我们在创建完 NSBlockOperation 后,还可以在向 operation 中添加任务,在这种情况下,系统会自动为我们开启新的线程异步执行所有的任务
提交给队列的异步执行
1 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 2 3 // 任务A 4 5 }]; 6 7 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 8 9 [queue addOperation:blockOperation];创建一个 NSBlockOperation 对象并添加任务,之后提交给队列异步执行,这种情况下系统也会自动为我们开启子线程,然后在子线程中异步执行任务
自定义Operation
有时系统给我们提供的 Operation 并不好用,这时我们就需要做自己定义 Operation
- 建立一个类(例如:NSDownloadImageOperation)继承自 NSOperation
- 重写 NSDownloadImageOperation 中的 main 方法,在 main 方法中实现我们想要的执行任务
- 在 main 方法中自己创建自动释放池,因为如果是异步操作的话,就无法访问主线程中的自动释放池
- 可能操作会被停止,所以我们要在 main 方法中经常通过 isCancelled 方法判断是否操作被停止,然后做出相应的响应
其它属性
Operation 有一个 completionBlock 属性,用来监听 Operation 操作完成后,需要执行操作
NSOperationQueue: 调度提交的 Operation
1. 将 Operation 添加给队列
1 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 2 3 [queue addOperation:operation];
2. 直接给队列添加 block 任务
1 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 2 3 [queue addOperationWithBlock:^{ 4 5 // 任务 6 7 }];3. 队列的最大并发数: 在同一时间,能有多少条线程执行操作用 maxConcurrentOperationCount 属性设置最大并发数
1 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 2 3 for (int i = 0; i < 3; ++i) { 4 5 [NSThread sleepForTimeInterval:.001]; 6 7 NSLog(@"%@", [NSThread currentThread]); 8 9 } 10 11 }]; 12 13 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 14 15 [queue addOperation:blockOperation]; 16 17 [queue addOperationWithBlock:^{ 18 19 for (int i = 0; i < 3; ++i) { 20 21 [NSThread sleepForTimeInterval:.001]; 22 23 NSLog(@"%@", [NSThread currentThread]); 24 25 } 26 27 }]; 28 29 queue.maxConcurrentOperationCount = 2;
由上面的结果,我们可以得到在同意时间最大并发线程的条数是2,尽管线程 number 已经开到3
4. 队列的取消
通过 cancelAllOperations 方法取消所有的Operation
5. 队列的挂起与回复
通过 setSuspended: 方法将队列挂起(YES)、恢复(NO)
6. 操作之间的先后顺序: NSOperation之间可以设置依赖来保证执行顺序
1 [operationB addDependency:operationA]; // 操作B依赖于操作A, 操作A在操作B之前执行
还可以在不同queue的NSOperation之间创建依赖关系
执行顺序: Operation B -> Operation 1 -> Operation 2 -> Operation C -> Operation 3 -> Operation D
Operation A 与 Operation 4 异步执行