最近学习了多线程编程 NSOperationQueue ,才比较清楚的明白了同步/异步,阻塞/非阻塞所表达的不同含义:所谓的同步/异步是对你得到消息的方式的描述,而阻塞/非阻塞则是你怎么样处理事情的做法,他们讲述的是不同层面的概念。
现在来讲述一下可以实现多线程的三种方式中的 NSOperation 类。使用NSOperation和NSOperationQueue实现多线程编程,实现步骤大致是这样的:
1> 先将需要执行的操作封装到一个NSOperation对象中
2> 然后将NSOperation对象添加到NSOperationQueue中
3> 系统会自动将NSOperation中封装的操作放到一条新线程中执行
而由于 NSOperation 是一个抽象类,所以它的功能只能有其子类 NSBlockOperation 和 SInvocationOperation 来实现。
NSBlockOperation 的使用
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"*执行第1次操作,线程:%@", [NSThread currentThread]);
}];
[operation addExecutionBlock:^() {
NSLog(@"**又执行了1个新的操作,线程:%@", [NSThread currentThread]);
}];
// 开始执行任务
[operation start];
注:默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作。只有将operation放到一个NSOperationQueue中,才会异步执行操作。
NSInvocationOperation 的使用
ration2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downLoadImage:) object:URL];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation2];
如果是有刷新界面的操作,那么必须将这个操作交给主线程来完成。
自定义 NSOperation 类
由于 NSOperation 类功能比较少, 一般情况下我们可以自定义一个 NSOperation 类。要定制这样的一个操作,可以遵循以下步骤:
- 继承 NSOperation 类
- 重写“main”方法
- 在“main”方法中创建一个“automaticreleasepool“
- 将你的代码放在”autoreleasepool“中
例子:
* .h 文件
#import <Foundation/Foundation.h>
@interface MyLengthyOperation : NSOperation
@property (nonatomic, strong, readonly) NSString *mark;
- (instancetype)initWithMark:(NSString *)mark;
@end
* .m 文件
#import "MyLengthyOperation.h"
@interface MyLengthyOperation ()
@property (nonatomic, strong, readwrite) NSString *mark;
@end
@implementation MyLengthyOperation
- (instancetype)initWithMark:(NSString *)mark {
self = [super init];
if (self) {
self.mark = mark;
}
return self;
}
- (void)main {
@autoreleasepool {
for (int i = 0; i < 100; i ++) {
if (self.isCancelled) {
break;
}
NSLog(@"%@ - %f", self.mark, sqrt(i));
}
}
}
@end
基本操作
// 初始化任务
MyLengthyOperation *operation_1 = [[MyLengthyOperation alloc] initWithMark:@"operation_1"];
MyLengthyOperation *operation_2 = [[MyLengthyOperation alloc] initWithMark:@"operation_2"];
// 设置任务的优先级
[operation_1 setQueuePriority:NSOperationQueuePriorityVeryLow];
[operation_2 setQueuePriority:NSOperationQueuePriorityHigh];
// 添加从属关系
[operation_2 addDependency:operation_1]; (任务2在任务1结束后才会执行)
// 初始化队列
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
myQueue.name = @"下载队列";
// 将一个简单的任务队列添加进队列中 (使用 Block 回调方式)
NSURL *aURL = [NSURL URLWithString:URL];
NSData *data = [NSData dataWithContentsOfURL:aURL];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImage *image = [[UIImage alloc] initWithData:data];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}];
}];
// 设置任务队列的最大并发数
myQueue.maxConcurrentOperationCount = 4;
// 添加进任务队列中执行
[myQueue addOperation:operation_1];
[myQueue addOperation:operation_2];
// 取消所有操作
[myQueue cancelAllOperations];
// 执行延时的操作(将执行代码放置在 block 中)
- (void)execute:(dispatch_block_t)block afterDelay:(int64_t)delta {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta), dispatch_get_main_queue(), block);
}
// 挂起操作
[myQueue setSuspended:YES];
// 取消任务
[operation_1 cancel];
// 任务完成后的回调可以表示任务已经结束
[operation_1 setCompletionBlock:^{
NSLog(@"任务1结束");
}];
[operation_2 setCompletionBlock:^{
NSLog(@"任务2结束");
}];