美文网首页多线程 & 网络
iOS多线程:NSOperation

iOS多线程:NSOperation

作者: 码小菜 | 来源:发表于2020-04-23 14:41 被阅读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,并发:需要实现startexecutingfinishedasynchronous方法

    // 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)}
    

    相关文章

      网友评论

        本文标题:iOS多线程:NSOperation

        本文链接:https://www.haomeiwen.com/subject/opesvhtx.html