iOS浅谈多线程之NSOperation

NSInvocationOperation

1、在主线程中使用

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSURL *url = [NSURL URLWithString:@"abc"] ;
    NSInvocationOperation *inv = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImgFromURL:) object:url];
    [inv start];
}
- (void)downloadImgFromURL:(NSURL *)url {
    NSLog(@"%@___%@",url,[NSThread currentThread]);
}
2018-10-10 14:29:42.285163+0800 Visit_Thread[4244:242395] abc___<NSThread: 0x60000006ea80>{number = 1, name = main}

2、多线程

maxConcurrentOperationCount小于当前任务数时会出现这样的情况(很容易理解3个任务,2条线程):

2条线程跑满2个任务,当一个线程中的任务执行完毕,再从队列中去取新的任务
如果设置最大并发数为1,那么任务将会串行执行(在不同的线程执行,但是执行顺序是串行的)
注意:串行执行任务 不等于 只开一条线程
如果设置最大并发数为0,那么任务将不会执行

如果设置最大并发数为-1,表示最大并发数不受限制

- (void)test7 {
     NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    queue.maxConcurrentOperationCount = 2;
    NSURL *url = [NSURL URLWithString:@"abc"] ;
    NSInvocationOperation *task1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImgFromURL1:) object:url];
    [queue addOperation:task1];
    NSInvocationOperation *task2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImgFromURL2:) object:url];
    [queue addOperation:task2];
    NSInvocationOperation *task3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImgFromURL3:) object:url];
    [queue addOperation:task3];
    NSLog(@"end");
}
- (void)downloadImgFromURL1:(NSURL *)url {
    for (int i = 0; i < 3; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1___%@",[NSThread currentThread]);
    }
    
}
- (void)downloadImgFromURL2:(NSURL *)url {
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2___%@",[NSThread currentThread]);
    }
}
- (void)downloadImgFromURL3:(NSURL *)url {
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"3___%@",[NSThread currentThread]);
    }
}
2018-10-10 14:58:31.460019+0800 Visit_Thread[4774:280702] start
2018-10-10 14:58:31.460932+0800 Visit_Thread[4774:280702] end
2018-10-10 14:58:33.463473+0800 Visit_Thread[4774:280744] 2___<NSThread: 0x60400007b840>{number = 3, name = (null)}
2018-10-10 14:58:33.463479+0800 Visit_Thread[4774:280746] 1___<NSThread: 0x60000066a980>{number = 4, name = (null)}
2018-10-10 14:58:35.468851+0800 Visit_Thread[4774:280744] 2___<NSThread: 0x60400007b840>{number = 3, name = (null)}
2018-10-10 14:58:35.468870+0800 Visit_Thread[4774:280746] 1___<NSThread: 0x60000066a980>{number = 4, name = (null)}
2018-10-10 14:58:37.474366+0800 Visit_Thread[4774:280746] 1___<NSThread: 0x60000066a980>{number = 4, name = (null)}
2018-10-10 14:58:37.474367+0800 Visit_Thread[4774:280744] 2___<NSThread: 0x60400007b840>{number = 3, name = (null)}
2018-10-10 14:58:39.479901+0800 Visit_Thread[4774:280744] 2___<NSThread: 0x60400007b840>{number = 3, name = (null)}
2018-10-10 14:58:39.479903+0800 Visit_Thread[4774:280745] 3___<NSThread: 0x60400026a700>{number = 5, name = (null)}
2018-10-10 14:58:41.485467+0800 Visit_Thread[4774:280745] 3___<NSThread: 0x60400026a700>{number = 5, name = (null)}
2018-10-10 14:58:41.485467+0800 Visit_Thread[4774:280744] 2___<NSThread: 0x60400007b840>{number = 3, name = (null)}
2018-10-10 14:58:43.491001+0800 Visit_Thread[4774:280745] 3___<NSThread: 0x60400026a700>{number = 5, name = (null)}
2018-10-10 14:58:45.496507+0800 Visit_Thread[4774:280745] 3___<NSThread: 0x60400026a700>{number = 5, name = (null)}
2018-10-10 14:58:47.502031+0800 Visit_Thread[4774:280745] 3___<NSThread: 0x60400026a700>{number = 5, name = (null)}
如果最大线程数超过当前任务数,那么也只会开和当前任务数相同的线程,多个任务,并发执行:

queue.maxConcurrentOperationCount = 5;

2018-10-10 15:02:01.148009+0800 Visit_Thread[4837:285412] start
2018-10-10 15:02:01.148893+0800 Visit_Thread[4837:285412] end
2018-10-10 15:02:03.152383+0800 Visit_Thread[4837:285465] 2___<NSThread: 0x60000047cf40>{number = 5, name = (null)}
2018-10-10 15:02:03.152388+0800 Visit_Thread[4837:285467] 1___<NSThread: 0x60000047cdc0>{number = 3, name = (null)}
2018-10-10 15:02:03.152383+0800 Visit_Thread[4837:285468] 3___<NSThread: 0x60400026d1c0>{number = 4, name = (null)}
2018-10-10 15:02:05.155475+0800 Visit_Thread[4837:285467] 1___<NSThread: 0x60000047cdc0>{number = 3, name = (null)}
2018-10-10 15:02:05.155489+0800 Visit_Thread[4837:285468] 3___<NSThread: 0x60400026d1c0>{number = 4, name = (null)}
2018-10-10 15:02:05.155481+0800 Visit_Thread[4837:285465] 2___<NSThread: 0x60000047cf40>{number = 5, name = (null)}
2018-10-10 15:02:07.159810+0800 Visit_Thread[4837:285465] 2___<NSThread: 0x60000047cf40>{number = 5, name = (null)}
2018-10-10 15:02:07.159821+0800 Visit_Thread[4837:285467] 1___<NSThread: 0x60000047cdc0>{number = 3, name = (null)}
2018-10-10 15:02:07.159815+0800 Visit_Thread[4837:285468] 3___<NSThread: 0x60400026d1c0>{number = 4, name = (null)}
2018-10-10 15:02:09.163067+0800 Visit_Thread[4837:285465] 2___<NSThread: 0x60000047cf40>{number = 5, name = (null)}
2018-10-10 15:02:09.163066+0800 Visit_Thread[4837:285468] 3___<NSThread: 0x60400026d1c0>{number = 4, name = (null)}
2018-10-10 15:02:11.168004+0800 Visit_Thread[4837:285468] 3___<NSThread: 0x60400026d1c0>{number = 4, name = (null)}
2018-10-10 15:02:11.168000+0800 Visit_Thread[4837:285465] 2___<NSThread: 0x60000047cf40>{number = 5, name = (null)}

NSBlockOperation

1、在主线程中使用

如果任务开始之后再追加任务,程序会cache:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSBlockOperation addExecutionBlock:]: blocks cannot be added after the operation has started executing or finished

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"start");
    NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1___%@",[NSThread currentThread]);
    }];
    NSBlockOperation *task2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2___%@",[NSThread currentThread]);
    }];
    NSBlockOperation *task3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"3___%@",[NSThread currentThread]);
    }];
   


    //追加任务
    [task1 addExecutionBlock:^{
        NSLog(@"1+++%@",[NSThread currentThread]);
    }];
    [task2 addExecutionBlock:^{
        NSLog(@"2+++%@",[NSThread currentThread]);
    }];
    [task3 addExecutionBlock:^{
        NSLog(@"3+++%@",[NSThread currentThread]);
    }];
    
    [task3 start];//先开始,先执行
    [task1 start];
    [task2 start];
    NSLog(@"end");
}
2018-10-10 14:41:09.361581+0800 Visit_Thread[4436:258615] start
2018-10-10 14:41:09.361974+0800 Visit_Thread[4436:258615] 3___<NSThread: 0x60000007cf00>{number = 1, name = main}
2018-10-10 14:41:09.361975+0800 Visit_Thread[4436:259265] 3+++<NSThread: 0x6000006667c0>{number = 8, name = (null)}
2018-10-10 14:41:09.362169+0800 Visit_Thread[4436:258615] 1___<NSThread: 0x60000007cf00>{number = 1, name = main}
2018-10-10 14:41:09.362182+0800 Visit_Thread[4436:259265] 1+++<NSThread: 0x6000006667c0>{number = 8, name = (null)}
2018-10-10 14:41:09.362635+0800 Visit_Thread[4436:259265] 2+++<NSThread: 0x6000006667c0>{number = 8, name = (null)}
2018-10-10 14:41:09.362643+0800 Visit_Thread[4436:258615] 2___<NSThread: 0x60000007cf00>{number = 1, name = main}
2018-10-10 14:41:09.362886+0800 Visit_Thread[4436:258615] end


2018-10-10 14:40:22.773672+0800 Visit_Thread[4436:258615] start
2018-10-10 14:40:22.774083+0800 Visit_Thread[4436:258615] 3___<NSThread: 0x60000007cf00>{number = 1, name = main}
2018-10-10 14:40:22.774114+0800 Visit_Thread[4436:258911] 3+++<NSThread: 0x60400046fc80>{number = 5, name = (null)}
2018-10-10 14:40:22.774752+0800 Visit_Thread[4436:258911] 1+++<NSThread: 0x60400046fc80>{number = 5, name = (null)}
2018-10-10 14:40:22.774753+0800 Visit_Thread[4436:258615] 1___<NSThread: 0x60000007cf00>{number = 1, name = main}
2018-10-10 14:40:22.774943+0800 Visit_Thread[4436:258615] 2___<NSThread: 0x60000007cf00>{number = 1, name = main}
2018-10-10 14:40:22.774951+0800 Visit_Thread[4436:258911] 2+++<NSThread: 0x60400046fc80>{number = 5, name = (null)}
2018-10-10 14:40:22.775110+0800 Visit_Thread[4436:258615] end

通过打印结果可知:先开始,先执行;
但是开始的任务中,是先执行原任务还是先执行追加任务,这个是不确定的;
原任务是在主线程中执行的,但是追加的任务都是在子线程中执行的;

多线程

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//     queue.maxConcurrentOperationCount = 5;
    NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1___%@",[NSThread currentThread]);
        }
    }];
    NSBlockOperation *task2 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2___%@",[NSThread currentThread]);
        }
    }];
    NSBlockOperation *task3 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3___%@",[NSThread currentThread]);
        }
    }];
    //追加任务
    [task1 addExecutionBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:1];
            NSLog(@"1+++%@",[NSThread currentThread]);
        }
    }];
    [task2 addExecutionBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2+++%@",[NSThread currentThread]);
        }
    }];
    [task3 addExecutionBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:3];
            NSLog(@"3+++%@",[NSThread currentThread]);
        }
    }];
    [queue addOperation:task1];
    [queue addOperation:task2];
    [queue addOperation:task3];
    NSLog(@"end");
}
2018-10-10 15:13:38.464338+0800 Visit_Thread[5027:297309] start
2018-10-10 15:13:38.464920+0800 Visit_Thread[5027:297309] end
2018-10-10 15:13:39.465737+0800 Visit_Thread[5027:297386] 1+++<NSThread: 0x60400027e980>{number = 3, name = (null)}
2018-10-10 15:13:40.469689+0800 Visit_Thread[5027:297364] 2___<NSThread: 0x604000465c40>{number = 5, name = (null)}
2018-10-10 15:13:40.469701+0800 Visit_Thread[5027:297365] 1___<NSThread: 0x604000465b80>{number = 4, name = (null)}
2018-10-10 15:13:40.469708+0800 Visit_Thread[5027:297386] 1+++<NSThread: 0x60400027e980>{number = 3, name = (null)}
2018-10-10 15:13:40.469735+0800 Visit_Thread[5027:297367] 3___<NSThread: 0x600000670640>{number = 6, name = (null)}
2018-10-10 15:13:40.469735+0800 Visit_Thread[5027:297385] 2+++<NSThread: 0x600000670880>{number = 7, name = (null)}
2018-10-10 15:13:41.468790+0800 Visit_Thread[5027:297366] 3+++<NSThread: 0x604000465dc0>{number = 8, name = (null)}
2018-10-10 15:13:41.475239+0800 Visit_Thread[5027:297386] 1+++<NSThread: 0x60400027e980>{number = 3, name = (null)}
2018-10-10 15:13:42.475216+0800 Visit_Thread[5027:297367] 3___<NSThread: 0x600000670640>{number = 6, name = (null)}
2018-10-10 15:13:42.475216+0800 Visit_Thread[5027:297365] 1___<NSThread: 0x604000465b80>{number = 4, name = (null)}
2018-10-10 15:13:42.475227+0800 Visit_Thread[5027:297364] 2___<NSThread: 0x604000465c40>{number = 5, name = (null)}
2018-10-10 15:13:42.475260+0800 Visit_Thread[5027:297385] 2+++<NSThread: 0x600000670880>{number = 7, name = (null)}
2018-10-10 15:13:44.469294+0800 Visit_Thread[5027:297366] 3+++<NSThread: 0x604000465dc0>{number = 8, name = (null)}
2018-10-10 15:13:44.479592+0800 Visit_Thread[5027:297364] 2___<NSThread: 0x604000465c40>{number = 5, name = (null)}
2018-10-10 15:13:44.479596+0800 Visit_Thread[5027:297367] 3___<NSThread: 0x600000670640>{number = 6, name = (null)}
2018-10-10 15:13:44.479592+0800 Visit_Thread[5027:297365] 1___<NSThread: 0x604000465b80>{number = 4, name = (null)}
2018-10-10 15:13:44.479641+0800 Visit_Thread[5027:297385] 2+++<NSThread: 0x600000670880>{number = 7, name = (null)}
2018-10-10 15:13:47.471226+0800 Visit_Thread[5027:297366] 3+++<NSThread: 0x604000465dc0>{number = 8, name = (null)}

NSOperation的暂停、恢复和取消

- (IBAction)start:(id)sender {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    _queue = queue;
         queue.maxConcurrentOperationCount = 1;
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"1___%@",[NSThread currentThread]);
        }
    }];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"2___%@",[NSThread currentThread]);
        }
    }];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"3___%@",[NSThread currentThread]);
        }
    }];
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:2];
            NSLog(@"4___%@",[NSThread currentThread]);
        }
    }];
    NSLog(@"end");
}
- (IBAction)suspend:(id)sender {
    NSLog(@"暂停");
    //不能暂停正在处于执行状态的任务
    [_queue setSuspended:YES];
}
- (IBAction)goOn:(id)sender {
    NSLog(@"继续");
    [_queue setSuspended:NO];
}
- (IBAction)cancel:(id)sender {
    NSLog(@"取消");
    //取消之后,不能恢复
    [_queue cancelAllOperations];
}

打印结果:

2018-10-10 17:05:36.939569+0800 Visit_Thread[6591:388486] start
2018-10-10 17:05:36.940215+0800 Visit_Thread[6591:388486] end
2018-10-10 17:05:38.945240+0800 Visit_Thread[6591:388556] 1___<NSThread: 0x604000462f00>{number = 3, name = (null)}
2018-10-10 17:05:40.948462+0800 Visit_Thread[6591:388556] 1___<NSThread: 0x604000462f00>{number = 3, name = (null)}
2018-10-10 17:05:41.736979+0800 Visit_Thread[6591:388486] 暂停
2018-10-10 17:05:42.948923+0800 Visit_Thread[6591:388556] 1___<NSThread: 0x604000462f00>{number = 3, name = (null)}
2018-10-10 17:06:01.016564+0800 Visit_Thread[6591:388486] 继续
2018-10-10 17:06:03.022025+0800 Visit_Thread[6591:388809] 2___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:05.027504+0800 Visit_Thread[6591:388809] 2___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:06.148510+0800 Visit_Thread[6591:388486] 暂停
2018-10-10 17:06:07.028798+0800 Visit_Thread[6591:388809] 2___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:09.031857+0800 Visit_Thread[6591:388809] 2___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:11.032833+0800 Visit_Thread[6591:388809] 2___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:14.879380+0800 Visit_Thread[6591:388486] 继续
2018-10-10 17:06:16.882917+0800 Visit_Thread[6591:388809] 3___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:18.885551+0800 Visit_Thread[6591:388809] 3___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:20.889610+0800 Visit_Thread[6591:388809] 3___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:22.890000+0800 Visit_Thread[6591:388809] 3___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:24.893687+0800 Visit_Thread[6591:388809] 3___<NSThread: 0x604000463ec0>{number = 4, name = (null)}
2018-10-10 17:06:26.896813+0800 Visit_Thread[6591:388893] 4___<NSThread: 0x60400026e640>{number = 5, name = (null)}
2018-10-10 17:06:28.898334+0800 Visit_Thread[6591:388893] 4___<NSThread: 0x60400026e640>{number = 5, name = (null)}
2018-10-10 17:06:30.898909+0800 Visit_Thread[6591:388893] 4___<NSThread: 0x60400026e640>{number = 5, name = (null)}
2018-10-10 17:06:32.212768+0800 Visit_Thread[6591:388486] 取消

结合打印结果可知:

maxConcurrentOperationCount为1时串行执行
串行执行不等于只开一条线程
不能暂停正在处于执行状态的任务
同样的,也不能取消正在执行的任务,必须要等当前任务执行完毕才能取消
任务取消之后,便不能恢复

继承NSOperation

#import <UIKit/UIKit.h>

@interface DownloadImgOperation : NSOperation
- (instancetype)initWithURL:(NSURL *)url imageView:(UIImageView *)imageView;
@end
#import "DownloadImgOperation.h"

@interface DownloadImgOperation()
@property (strong, nonatomic) NSURL *url;
@property (strong, nonatomic) UIImageView *imageView;
@end
@implementation DownloadImgOperation
- (void)main {//重写main方法
    NSData *data = [[NSData alloc]initWithContentsOfURL:self.url];
    UIImage *image = [[UIImage alloc]initWithData:data];
    if (image != nil) {
        [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
    }else {
        NSLog(@"download error");
    }
    
}
- (instancetype)initWithURL:(NSURL *)url imageView:(UIImageView *)imageView {
    if (self = [super init]) {
        self.imageView = imageView;
        self.url = url;
    }
    return self;
}
- (void)updateUI:(UIImage *)image {
    self.imageView.image =image;
}
@end

如果是在自定义Operation中的main方法中有耗时操作,那么需要特别处理:

- (void)main {//重写main方法
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1___%@",[NSThread currentThread]);
    }
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2___%@",[NSThread currentThread]);
    }
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"3___%@",[NSThread currentThread]);
    }
}

调用注意点:

1、暂定功能不起作用,因为暂停是针对多个Operation的,开始时只有一个,暂停时需要等这个Operation执行完毕,所以没有意义,取消也是如此。那么继续也便没有意义。
2、但是可以实现通过改进,来实现取消功能(在main方法中做更改):
- (IBAction)start:(id)sender {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    _queue = queue;
    queue.maxConcurrentOperationCount = 1;
    DownloadImgOperation *operation = [[DownloadImgOperation alloc]init];
    [_queue addOperation:operation];
    NSLog(@"end");
}
- (IBAction)cancel:(id)sender {
    NSLog(@"取消");
    [_queue cancelAllOperations];
}

更改main方法:

- (void)main {//重写main方法
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        //虽然在此处可以做到精确控制,但是如果循环次数太多,每次都需要做判断,所以不建议这样使用
//        if(self.isCancelled) return;
        NSLog(@"1___%@",[NSThread currentThread]);
    }
    if(self.isCancelled) return;
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2___%@",[NSThread currentThread]);
    }
    if(self.isCancelled) return;
    for (int i = 0; i < 5; i++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"3___%@",[NSThread currentThread]);
    }
}

设置NSOperation的依赖与监听

- (IBAction)start:(id)sender {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    NSOperationQueue *queue2 = [[NSOperationQueue alloc]init];
    NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:1];
            NSLog(@"1___%@",[NSThread currentThread]);
        }
    }];
    NSBlockOperation *task2 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            [NSThread sleepForTimeInterval:1];
            NSLog(@"2___%@",[NSThread currentThread]);
        }
    }];
    NSBlockOperation *task3 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 5; i++) {
            [NSThread sleepForTimeInterval:1];
            NSLog(@"3___%@",[NSThread currentThread]);
        }
    }];
    NSBlockOperation *task4 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            [NSThread sleepForTimeInterval:1];
            NSLog(@"4___%@",[NSThread currentThread]);
        }
    }];
    //设置依赖:
    //
    [task2 addDependency:task1];//必须等task1的任务执行完毕task2才能执行
    [task3 addDependency:task2];//必须等task2的任务执行完毕task3才能执行
    task1.completionBlock = ^ {
        NSLog(@"task1执行完毕了————%@",[NSThread currentThread]);
    };
    [queue addOperation:task1];
    [queue2 addOperation:task2];
    [queue2 addOperation:task3];
    [queue addOperation:task4];
    NSLog(@"end");
}
打印结果:
2018-10-10 18:25:08.234783+0800 Visit_Thread[7925:466651] start
2018-10-10 18:25:08.235548+0800 Visit_Thread[7925:466651] end
2018-10-10 18:25:09.238803+0800 Visit_Thread[7925:466803] 4___<NSThread: 0x600000478880>{number = 4, name = (null)}
2018-10-10 18:25:09.238801+0800 Visit_Thread[7925:466707] 1___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:10.242784+0800 Visit_Thread[7925:466803] 4___<NSThread: 0x600000478880>{number = 4, name = (null)}
2018-10-10 18:25:10.242784+0800 Visit_Thread[7925:466707] 1___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:11.247918+0800 Visit_Thread[7925:466803] 4___<NSThread: 0x600000478880>{number = 4, name = (null)}
2018-10-10 18:25:11.247918+0800 Visit_Thread[7925:466707] 1___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:11.248278+0800 Visit_Thread[7925:466707] task1执行完毕了————<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:12.248466+0800 Visit_Thread[7925:466810] 2___<NSThread: 0x60000047f3c0>{number = 5, name = (null)}
2018-10-10 18:25:13.252236+0800 Visit_Thread[7925:466810] 2___<NSThread: 0x60000047f3c0>{number = 5, name = (null)}
2018-10-10 18:25:14.256300+0800 Visit_Thread[7925:466810] 2___<NSThread: 0x60000047f3c0>{number = 5, name = (null)}
2018-10-10 18:25:15.261807+0800 Visit_Thread[7925:466810] 2___<NSThread: 0x60000047f3c0>{number = 5, name = (null)}
2018-10-10 18:25:16.267055+0800 Visit_Thread[7925:466810] 2___<NSThread: 0x60000047f3c0>{number = 5, name = (null)}
2018-10-10 18:25:17.267466+0800 Visit_Thread[7925:466707] 3___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:18.272417+0800 Visit_Thread[7925:466707] 3___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:19.275128+0800 Visit_Thread[7925:466707] 3___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:20.280244+0800 Visit_Thread[7925:466707] 3___<NSThread: 0x600000476900>{number = 3, name = (null)}
2018-10-10 18:25:21.281868+0800 Visit_Thread[7925:466707] 3___<NSThread: 0x600000476900>{number = 3, name = (null)}

NSOperation的线程间的通信

1、方式1
- (IBAction)start:(id)sender {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//    [queue addOperationWithBlock:^{
//        //coding
//    }];
    __block UIImage *img ;
    NSBlockOperation *task = [NSBlockOperation blockOperationWithBlock:^{
        NSURL *url = [NSURL URLWithString:@"http://c.hiphotos.baidu.com/image/h%3D300/sign=c635d3753efa828bce239be3cd1f41cd/0eb30f2442a7d933b29eb303a04bd11373f0018f.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        img = [UIImage imageWithData:data];
    }];
    task.completionBlock = ^ {
        NSLog(@"task1执行完毕了————%@",[NSThread currentThread]);
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"%@",[NSThread currentThread]);
            self.imgView.image = img;
        }];
    };
    [queue addOperation:task];
    NSLog(@"end");
}
2、方式2
- (IBAction)start:(id)sender {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperationWithBlock:^{
        //coding
        NSLog(@"%@",[NSThread currentThread]);
    }];
    __block UIImage *img ;
    NSBlockOperation *task = [NSBlockOperation blockOperationWithBlock:^{
        NSURL *url = [NSURL URLWithString:@"http://c.hiphotos.baidu.com/image/h%3D300/sign=c635d3753efa828bce239be3cd1f41cd/0eb30f2442a7d933b29eb303a04bd11373f0018f.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *img = [UIImage imageWithData:data];
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imgView.image = img;
        }];
    }];
    [queue addOperation:task];
    NSLog(@"end");
}

练习:将2张图片合成一张图片并展示

- (IBAction)start:(id)sender {
    NSLog(@"start");
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    __block UIImage *img1 ;
    NSBlockOperation *task1 = [NSBlockOperation blockOperationWithBlock:^{
        NSURL *url = [NSURL URLWithString:@"http://c.hiphotos.baidu.com/image/h%3D300/sign=c635d3753efa828bce239be3cd1f41cd/0eb30f2442a7d933b29eb303a04bd11373f0018f.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        img1 = [UIImage imageWithData:data];
    }];
    __block UIImage *img2 ;
    NSBlockOperation *task2 = [NSBlockOperation blockOperationWithBlock:^{
        NSURL *url = [NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/h%3D300/sign=b48b76f776899e51678e3c1472a6d990/e824b899a9014c08ef778daf077b02087bf4f468.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        img2 = [UIImage imageWithData:data];
    }];
    NSBlockOperation *task3 = [NSBlockOperation blockOperationWithBlock:^{
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));
        [img1 drawInRect:CGRectMake(0, 0, 200, 100)];
        [img2 drawInRect:CGRectMake(0, 100, 200, 100)];
        UIImage *combinImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [[NSOperationQueue mainQueue]addOperationWithBlock:^{
            self.imgView.image = combinImg;
        }];
    }];
    
    [task3 addDependency:task1];
    [task3 addDependency:task2];
    [queue addOperation:task1];
    [queue addOperation:task2];
    [queue addOperation:task3];
    NSLog(@"end");
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容