iOS多线程:NSOperation
2020-04-23 本文已影响0人
码小菜
别墅
目录
一,NSOperation
二,NSInvocationOperation
三,NSBlockOperation
四,NSOperationQueue(一)
五,NSOperationQueue(二)
六,自定义NSOperation
一,NSOperation
1,它是一个抽象类,不能直接使用,只能使用其子类
-
NSInvocationOperation
-
NSBlockOperation
-
自定义
NSOperation
2,执行方式
-
同步执行:调用
start
方法 -
异步执行:添加到
NSOperationQueue
中
二,NSInvocationOperation
1,initWithTarget:
- (void)viewDidLoad {
[super viewDidLoad];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(performOperation) object:nil];
[operation start];
}
- (void)performOperation {
NSLog(@"%s---%@", __func__, [NSThread currentThread]);
}
// 打印
-[ViewController performOperation]---<NSThread: 0x60000313fc40>{number = 1, name = main}
2,initWithInvocation:
- (void)viewDidLoad {
[super viewDidLoad];
NSMethodSignature *signature = [self methodSignatureForSelector:@selector(performOperation)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = @selector(performOperation);
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invocation];
[operation start];
}
// 打印
-[ViewController performOperation]---<NSThread: 0x6000014490c0>{number = 1, name = main}
三,NSBlockOperation
1,一个任务:同步执行
- (void)viewDidLoad {
[super viewDidLoad];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock---%@", [NSThread currentThread]);
}];
[operation start];
}
// 打印
blockOperationWithBlock---<NSThread: 0x60000315ad40>{number = 1, name = main}
2,多个任务:其中一个同步执行,其他的都异步执行
- (void)viewDidLoad {
[super viewDidLoad];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock---%@", [NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"addExecutionBlock1---%@", [NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"addExecutionBlock2---%@", [NSThread currentThread]);
}];
[operation start];
}
// 打印
blockOperationWithBlock---<NSThread: 0x60000119ad00>{number = 5, name = (null)}
addExecutionBlock1---<NSThread: 0x6000011edf80>{number = 6, name = (null)}
addExecutionBlock2---<NSThread: 0x60000119cf80>{number = 1, name = main}
四,NSOperationQueue(一)
1,添加到队列中的操作都是异步执行
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(performOperation) object:nil];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock---%@", [NSThread currentThread]);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperationWithBlock:^{
NSLog(@"addOperationWithBlock---%@", [NSThread currentThread]);
}];
}
- (void)performOperation {
NSLog(@"%s---%@", __func__, [NSThread currentThread]);
}
// 打印
blockOperationWithBlock---<NSThread: 0x600003d8e400>{number = 6, name = (null)}
addOperationWithBlock---<NSThread: 0x600003d98800>{number = 7, name = (null)}
-[ViewController performOperation]---<NSThread: 0x600003db1a00>{number = 4, name = (null)}
2,添加依赖可以设置执行顺序
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
}];
[operation1 addDependency:operation2];
[operation2 addDependency:operation3];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
// 打印
blockOperationWithBlock3---<NSThread: 0x6000002c2a40>{number = 5, name = (null)}
blockOperationWithBlock2---<NSThread: 0x6000002c2a40>{number = 5, name = (null)}
blockOperationWithBlock1---<NSThread: 0x6000002ce9c0>{number = 6, name = (null)}
3,优先级不能决定执行顺序
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
}];
operation1.queuePriority = NSOperationQueuePriorityLow;
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
}];
operation2.queuePriority = NSOperationQueuePriorityNormal;
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
}];
operation3.queuePriority = NSOperationQueuePriorityHigh;
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
// 打印
blockOperationWithBlock2---<NSThread: 0x6000007519c0>{number = 6, name = (null)}
blockOperationWithBlock1---<NSThread: 0x60000075a280>{number = 5, name = (null)}
blockOperationWithBlock3---<NSThread: 0x6000007586c0>{number = 4, name = (null)}
4,设置队列的最大并发数
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
// 同时只能执行一个操作
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
sleep(1.0);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
// 打印
16:15:09.331128+0800 Demo[97301:24562664] blockOperationWithBlock1---<NSThread: 0x6000038741c0>{number = 7, name = (null)}
16:15:10.334874+0800 Demo[97301:24562666] blockOperationWithBlock2---<NSThread: 0x600003850d40>{number = 4, name = (null)}
16:15:11.340412+0800 Demo[97301:24562668] blockOperationWithBlock3---<NSThread: 0x6000038549c0>{number = 5, name = (null)}
5,添加栅栏操作
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock4---%@", [NSThread currentThread]);
sleep(1.0);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addBarrierBlock:^{
NSLog(@"addBarrierBlock---%@", [NSThread currentThread]);
sleep(1.0);
}];
[queue addOperation:operation3];
[queue addOperation:operation4];
}
// 打印
07:03:04.497862+0800 Demo[98215:24588685] blockOperationWithBlock1---<NSThread: 0x600000b69580>{number = 6, name = (null)}
07:03:04.497866+0800 Demo[98215:24588689] blockOperationWithBlock2---<NSThread: 0x600000b40080>{number = 3, name = (null)}
07:03:05.503058+0800 Demo[98215:24588689] addBarrierBlock---<NSThread: 0x600000b40080>{number = 3, name = (null)}
07:03:06.504957+0800 Demo[98215:24588689] blockOperationWithBlock4---<NSThread: 0x600000b40080>{number = 3, name = (null)}
07:03:06.504976+0800 Demo[98215:24588685] blockOperationWithBlock3---<NSThread: 0x600000b69580>{number = 6, name = (null)}
五,NSOperationQueue(二)
1,暂停和恢复
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
sleep(1.0);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
queue.suspended = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
queue.suspended = NO;
});
});
}
// 打印
07:26:36.604627+0800 Demo[98630:24601404] blockOperationWithBlock1---<NSThread: 0x6000027c1a00>{number = 6, name = (null)}
07:26:37.608845+0800 Demo[98630:24601405] blockOperationWithBlock2---<NSThread: 0x6000027faf40>{number = 4, name = (null)}
07:26:40.693889+0800 Demo[98630:24601405] blockOperationWithBlock3---<NSThread: 0x6000027faf40>{number = 4, name = (null)}
2,取消操作
- 取消某个操作
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
sleep(3.0);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[operation2 cancel];
});
}
// 打印
07:46:44.497224+0800 Demo[98851:24610141] blockOperationWithBlock1---<NSThread: 0x600000098000>{number = 7, name = (null)}
07:46:47.501865+0800 Demo[98851:24610144] blockOperationWithBlock3---<NSThread: 0x6000000b1b80>{number = 6, name = (null)}
- 取消所有操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[queue cancelAllOperations];
});
// 打印
blockOperationWithBlock1---<NSThread: 0x60000360a980>{number = 5, name = (null)}
⚠️注意⚠️:正在执行的操作是无法取消的
3,监听操作执行完成
- 监听某个操作执行完成
1>
completionBlock
- (void)viewDidLoad { [super viewDidLoad]; NSOperationQueue *queue = [NSOperationQueue new]; NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"blockOperationWithBlock---%@", [NSThread currentThread]); sleep(3.0); }]; operation.completionBlock = ^{ NSLog(@"操作已执行完成---%@", [NSThread currentThread]); }; [queue addOperation:operation]; } // 打印 10:15:43.988124+0800 Demo[543:24663415] blockOperationWithBlock---<NSThread: 0x600003a7b240>{number = 6, name = (null)} 10:15:46.990208+0800 Demo[543:24663412] 操作已执行完成---<NSThread: 0x600003a46740>{number = 3, name = (null)}
2>
waitUntilFinished
- (void)viewDidLoad { [super viewDidLoad]; NSOperationQueue *queue = [NSOperationQueue new]; NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"blockOperationWithBlock---%@", [NSThread currentThread]); sleep(3.0); }]; [queue addOperation:operation]; // 会阻塞当前线程 [operation waitUntilFinished]; NSLog(@"操作已执行完成---%@", [NSThread currentThread]); } // 打印 10:18:14.938398+0800 Demo[570:24665122] blockOperationWithBlock---<NSThread: 0x600001fe4440>{number = 6, name = (null)} 10:18:17.943464+0800 Demo[570:24665010] 操作已执行完成---<NSThread: 0x600001f82d00>{number = 1, name = main}
- 监听所有操作执行完成
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
sleep(1.0);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
sleep(2.0);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock3---%@", [NSThread currentThread]);
sleep(3.0);
}];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
// 会阻塞当前线程
[queue waitUntilAllOperationsAreFinished];
NSLog(@"所有操作都已执行完成---%@", [NSThread currentThread]);
}
// 打印
17:34:04.224280+0800 Demo[1979:24709361] blockOperationWithBlock3---<NSThread: 0x6000013b4c00>{number = 5, name = (null)}
17:34:04.224284+0800 Demo[1979:24709359] blockOperationWithBlock1---<NSThread: 0x600001389100>{number = 6, name = (null)}
17:34:04.224280+0800 Demo[1979:24709365] blockOperationWithBlock2---<NSThread: 0x600001381ec0>{number = 7, name = (null)}
17:34:07.225338+0800 Demo[1979:24709300] 所有操作都已执行完成---<NSThread: 0x6000013f50c0>{number = 1, name = main}
4,监听操作的执行过程
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock1---%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperationWithBlock2---%@", [NSThread currentThread]);
}];
[operation1 addObserver:self
forKeyPath:@"ready"
options:NSKeyValueObservingOptionNew
context:nil];
[operation1 addObserver:self
forKeyPath:@"executing"
options:NSKeyValueObservingOptionNew
context:nil];
[operation1 addObserver:self
forKeyPath:@"finished"
options:NSKeyValueObservingOptionNew
context:nil];
[operation1 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context {
BOOL status = [change[NSKeyValueChangeNewKey] boolValue];
if ([keyPath isEqualToString:@"ready"]) {
if (status) {
NSLog(@"operation1已准备好");
} else {
NSLog(@"operation1未准备好");
}
} else if ([keyPath isEqualToString:@"executing"]) {
if (status) {
NSLog(@"operation1正在执行");
} else {
NSLog(@"operation1停止执行");
}
} else if ([keyPath isEqualToString:@"finished"]) {
if (status) {
NSLog(@"operation1已执行完成");
} else {
NSLog(@"operation1未执行完成");
}
}
}
// 打印
operation1未准备好
blockOperationWithBlock2---<NSThread: 0x600002aae900>{number = 6, name = (null)}
operation1已准备好
operation1正在执行
blockOperationWithBlock1---<NSThread: 0x600002abb780>{number = 4, name = (null)}
operation1停止执行
operation1已执行完成
5,线程通信
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[queue addOperationWithBlock:^{
NSLog(@"在子线程请求数据---%@", [NSThread currentThread]);
[mainQueue addOperationWithBlock:^{
NSLog(@"回主线程刷新UI---%@", [NSThread currentThread]);
}];
}];
}
// 打印
在子线程请求数据---<NSThread: 0x6000032d4540>{number = 7, name = (null)}
回主线程刷新UI---<NSThread: 0x6000032a6140>{number = 1, name = main}
六,自定义NSOperation
1,非并发:只需实现main
方法即可
// YJCustomOperation.h
@interface YJCustomOperation : NSOperation
- (instancetype)initWithBlock:(void(^)(void))block;
@end
// YJCustomOperation.m
@interface YJCustomOperation ()
@property (nonatomic, copy) void(^block)(void);
@end
@implementation YJCustomOperation
- (instancetype)initWithBlock:(void(^)(void))block {
self = [super init];
if (self) {
self.block = block;
}
return self;
}
- (void)main {
// 在此方法中无法访问主线程的自动释放池,所以需要手动创建
@autoreleasepool {
// 响应取消事件
if (self.isCancelled) return;
// 执行任务
if (self.block) {
self.block();
}
}
}
@end
// 使用
- (void)viewDidLoad {
[super viewDidLoad];
YJCustomOperation *operation = [[YJCustomOperation alloc] initWithBlock:^{
NSLog(@"initWithBlock---%@", [NSThread currentThread]);
}];
[operation start];
}
// 打印
initWithBlock---<NSThread: 0x600002254b40>{number = 1, name = main}
2,并发:需要实现start
、executing
、finished
、asynchronous
方法
// YJCustomOperation.h
@interface YJCustomOperation : NSOperation
- (instancetype)initWithBlock:(void(^)(void))block;
@end
// YJCustomOperation.m
@interface YJCustomOperation ()
@property (nonatomic, readwrite, getter=isExecuting) BOOL executing;
@property (nonatomic, readwrite, getter=isFinished) BOOL finished;
@property (nonatomic, copy) void(^block)(void);
@end
@implementation YJCustomOperation
@synthesize executing = _executing;
@synthesize finished = _finished;
- (instancetype)initWithBlock:(void(^)(void))block {
self = [super init];
if (self) {
self.block = block;
}
return self;
}
- (void)start {
@autoreleasepool {
self.executing = YES;
if (self.isCancelled) {
self.executing = NO;
self.finished = YES;
return;
};
if (self.block) {
self.block();
}
self.executing = NO;
self.finished = YES;
}
}
- (void)setExecuting:(BOOL)executing {
if (_executing != executing) {
// 手动发送KVO通知
[self willChangeValueForKey:@"executing"];
_executing = executing;
[self didChangeValueForKey:@"executing"];
}
}
- (void)setFinished:(BOOL)finished {
if (_finished != finished) {
[self willChangeValueForKey:@"finished"];
_finished = finished;
[self didChangeValueForKey:@"finished"];
}
}
- (BOOL)isExecuting {
return _executing;
}
- (BOOL)isFinished {
return _finished;
}
// 是否并发
- (BOOL)isAsynchronous {
return YES;
}
@end
// 使用
- (void)viewDidLoad {
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
YJCustomOperation *operation = [[YJCustomOperation alloc] initWithBlock:^{
NSLog(@"initWithBlock---%@", [NSThread currentThread]);
}];
[queue addOperation:operation];
}
// 打印
initWithBlock---<NSThread: 0x600000b3dc80>{number = 6, name = (null)}