美文网首页
多线程3

多线程3

作者: project_DLQ | 来源:发表于2016-10-20 17:29 被阅读0次

同步任务的作用

//需求:登录- 付费 - 下载 - 通知用户
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self CGDDemo];
}
/*
 1.同步任务只在当前线程执行
 2.同步任务之间是有执行的,前面一个同步任务不执行完,后面的同步任务无法执行
 */
-(void)CGDDemo{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //创在一个子线程的环境,让多个同步任务在子线程里面按顺序执行
    dispatch_async(queue, ^{
        //登录
        dispatch_sync(queue, ^{
            NSLog(@"登录:%@",[NSThread currentThread]);
        });
        //付费
        dispatch_sync(queue, ^{
            NSLog(@"付费:%@",[NSThread currentThread]);
        });
        dispatch_sync(queue, ^{
            NSLog(@"下载:%@",[NSThread currentThread]);
        });
        //通知用户
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"通知用户:%@",[NSThread currentThread]);
        });
    });
}

GCD阻塞(Barrier)

使用场景:
主要用于在多个异步操作完成之后,统一对非线程安全的对象进行操作
适合大规模数据的I/O(读写)操作

@interface ViewController ()

//图片数组
@property (strong,nonatomic) NSMutableArray *imagesM;

@end
//需求:异步下载多张图片,下载完成之后,把图片对象保存到数组
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //实例化数组:为什么要实例化?因为要向里面添加对象,需要一定的内存空间,不实例化就没有内存空间
    self.imagesM = [NSMutableArray array];
    [self downloadImages2];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSLog(@"%tu",self.imagesM.count);
}
//使用GCD阻塞:dispatch_barrier_async
-(void)downloadImages2{
    //使用GCD的barrier实现,必须使用自定义的并发队列
    //dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    //定义局部的队列
    dispatch_queue_t queue = dispatch_queue_create("hehe", DISPATCH_QUEUE_CONCURRENT);
    //循环的创建多个异步任务,同时下载多张图片
    for (int i = 0; i < 10; i++) {
        dispatch_async(queue, ^{
            //1.获取图片名字
            NSString *name = [NSString stringWithFormat:@"%02zd.jpg",(i%10+1)];
            //2.获取本地图片的本地URL
            NSURL *url = [[NSBundle mainBundle]URLForResource:name withExtension:nil];
            //3.获取image对象
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            //模拟网络延迟
            // [NSThread sleepForTimeInterval:0.5];
            NSLog(@"%@ - - %@",name,[NSThread currentThread]);
            //图片下载完成之后,需要保存到可变数组
            //有可能出现多尔衮线程同时向同一个角标插入图片对象
            //queue:只有当queue里面的任务都执行完,再执行barrier对应的任务
            //所以不能使用全局队列:因为全局对象是共享给整个APP使用的,只有一个,有可能其他界面用到了
            //barrier会在一个线程里面吧之前没有执行的代码,再执行一遍,会单开一个线程单独的操作非安全的类
            dispatch_barrier_async(queue, ^{
               NSLog(@"%@ - - %@",name,[NSThread currentThread]);
                [self.imagesM addObject:image];
            });
            
        });
    }
    
}

//错误演示
-(void)downloadImages{
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //循环的创建多个异步任务,同时下载多张图片
    for (int i = 0; i < 100000; i++) {
        dispatch_async(queue, ^{
                //1.获取图片名字
                NSString *name = [NSString stringWithFormat:@"%02zd.jpg",(i%10+1)];
                //2.获取本地图片的本地URL
                NSURL *url = [[NSBundle mainBundle]URLForResource:name withExtension:nil];
                //3.获取image对象
                NSData *data = [NSData dataWithContentsOfURL:url];
                UIImage *image = [UIImage imageWithData:data];
                //模拟网络延迟
               // [NSThread sleepForTimeInterval:0.5];
                NSLog(@"%@ - - %@",name,[NSThread currentThread]);
                //图片下载完成之后,需要保存到可变数组
                //有可能出现多尔衮线程同时向同一个角标插入图片对象
                [self.imagesM addObject:image];
            
        });
    }
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

GCD延迟操作

-(void)after2{
    
    NSLog(@"开始");
    
    
    //参数1:延迟时间:NSEC_PER_SEC 10亿纳秒(非常精确,比NSTimer要精确)
    dispatch_time_t when =dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
    //参数2:延迟任务执行的队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //参数3:延迟的任务
    dispatch_block_t block = ^{
        NSLog(@"哈哈 %@",[NSThread currentThread]);
    };
    //延迟默认是异步执行的
    //延迟多长时间,在哪个队列调度执行哪个异步任务
    //延迟默认是异步执行的
    dispatch_after(when, queue, block);
    NSLog(@"结束");

}

-(void)after{
    NSLog(@"开始");
    //延迟默认是异步执行的
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"哈哈 %@",[NSThread currentThread]);
    });
    NSLog(@"结束");
}

GCD一次性执行

dispatch_once_t 内部有一把锁,是能够保证 线程安全,而却是苹果公司推荐使用的
在开发中,有些代码指向就只执行一次

//验证一次性执行是否安全
-(void)onceDemo2{
    for (int i = 0; i < 1000; i++) {
         NSLog(@"gfdsdfghs");
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^{
                NSLog(@"鸟哥");
            });
        });
    }
   
    
}
//验证一次性执行的可靠性
-(void)onceDemo1{
    
    NSLog(@"start");
    //一次性执行就是准备好的代码块
    static dispatch_once_t onceToken;//静态区 onceToken的地址不会发生变化,是个long类型的值
    //原理:onceToken被保存在静态存储区,地址唯一,有个初始值是0;当第一次执行时,会检测初始值是否为0,如果是0就执行代码块,反之,就不执行代码块
    //提示:当第一次执行完完之后,会修改onceToken的值为非0的值
   
    NSLog(@"%ld",onceToken);
    dispatch_once(&onceToken, ^{
        //只被执行一次的代码
        NSLog(@"鸟哥");
    });

}

单例设计模式

/*
 once的使用场景:单例模式的设计
 单例模式
    1.对象有且只有一个
    2.保存在静态存储区
    3.声明周期和APP一样长
 单例的使用场景
    1.在APP中,必须有且只有一个对象的类,要设计成单例模式(音乐播放器...)
    2.在APP开发中,有些类,会经常频繁的使用,比如一些工具类(网络请求工具类,数据路管理工具类)
单例的缺点
    1.只要创建了单例对象,就会一直占用内存,直到这个程序退出,单例对象的内存空间才释放
    2.单例不能过多的使用,滥用
 系统单例
    1.NSFileManager/NSUserDefault/ NSNotifacationCenter....
 单例分两种:恶汉式和懒汉式,实际开发中使用懒汉式就够了,懒汉式仅做了解
 面试时:有可能手写单例
单例是一种是设计模式,类似于MVC..设计模式
开发中不需要重写跟开辟内存空间和实例化相关的任何方法
 */
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NetWorkTool *tool0 = [[NetWorkTool alloc] init];
    NetWorkTool *tool1 = [NetWorkTool shardTool];
    NetWorkTool *tool2 = [NetWorkTool shardTool];
    NSLog(@"%@ -- %@--%@",tool0,tool1,tool2);
    
    
    FMDBManager *manager0 = [[FMDBManager alloc] init];
    FMDBManager *manager1 = [FMDBManager sharedManager];
    FMDBManager *manager2 = [FMDBManager sharedManager];
    NSLog(@"%@ -- %@--%@",manager0,manager1,manager2);

    
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

懒汉式:

@interface NetWorkTool : NSObject

//单例的全局访问点,返回这个单例对象
//懒汉式单例:尽量创建的晚
+(instancetype)shardTool;

@end

@implementation NetWorkTool

+(instancetype)shardTool{
    //定义静态对象
    static NetWorkTool *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc]init];;
    });
    return instance;
}
@end

饿汉式:

@interface FMDBManager : NSObject

//全局访问点
//饿汉式
+(instancetype)sharedManager;
@end
@implementation FMDBManager
static id instance;
//当某个类第一次使用时就会调用一次
//线程安全的
+(void)initialize{
  instance = [[self alloc] init];
}

+(instancetype)sharedManager{
    
    return instance;
}

@end

GCD的调度组(Group)

实际开发中,有可能会常用
新浪微博中就会用到
group是监听一组异步任务是否执行结束,如果执行结束,就可以得到统一的通知

/*
 void
 dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block)
     {
         dispatch_retain(group);
         dispatch_group_enter(group);
         dispatch_async(queue, ^{
             block();
             dispatch_group_leave(group);
             dispatch_release(group);
     });
 }

 */
/*
 1.当enter < leave会崩溃
 2.当enter > leave会检测不到
 3.enter和leave必须成对出现
 */
-(void)groupDemo2{
    //组
    dispatch_group_t group = dispatch_group_create();
    //队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //异步下载图片A
    //向group里面添加标记
    dispatch_group_enter(group);
    //异步执行下载任务
    dispatch_async(queue, ^{
        //执行任务
        NSLog(@"假装下载图片A:%@",[NSThread currentThread]);
        //任务执行完之后,把标记从组里面移除
        dispatch_group_leave(group);
    });
    
    //下载图片B
    //向group里面添加标记
    dispatch_group_enter(group);
    //异步执行下载任务
    dispatch_async(queue, ^{
        //执行任务
        NSLog(@"假装下载图片B:%@",[NSThread currentThread]);
        //任务执行完之后,把标记从组里面移除
        dispatch_group_leave(group);
    });
    
    //下载图片C
    //向group里面添加标记
    dispatch_group_enter(group);
    //异步执行下载任务
    dispatch_async(queue, ^{
        //执行任务
        NSLog(@"假装下载图片C:%@",[NSThread currentThread]);
        //任务执行完之后,把标记从组里面移除
        dispatch_group_leave(group);
    });
    
    //监听
    dispatch_group_notify(group, queue, ^{
        NSLog(@"图片下载完了么?--%@",[NSThread currentThread]);
    });
}

//group监听一组异步任务是否执行结束
-(void)groupDemo{
    //组:
    dispatch_group_t group = dispatch_group_create();
    //队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //这个异步函数,是把异步任务添加到队列,并且向"组"(group)里面添加了一个标记
    dispatch_group_async(group, queue, ^{
        NSLog(@"假装下载图片A:%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"假装下载图片B:%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"假装下载图片C:%@",[NSThread currentThread]);
    });
    //监听group里面的任务是否执行完:一般检测到下载结束之后,在这里面刷新UI的操作
    //dispatch_group_notify 是在子线程执行的,需要回到主线程刷新UI
    //dispatch_group_notify:一旦检测到group里面的标记没有了,就开始调用dispatch_group_notify里面的方法
    dispatch_group_notify(group, queue, ^{
         NSLog(@"图片下载完了么?--%@",[NSThread currentThread]);
    });
   
    
}

NSOperation

NSOperation简介

  1. operation:操作的意思
  2. 是oc语言中 基于GCD的面向对象的操作
  3. 使用起来比GCD更加简单(面向对象)
  4. 提供一些用GCD不好实现的功能
/*
 NSOperation
 1.它是一个抽象类,无法直接使用;因为只有定义,无实现;实现交给子类;他的作用就是作为父类,约束子类"共有"的属性和方法
 2.子类
    NSInvocationOperation
    NSBlockOperation
 3.队列
    NSOperationQueue
 4.GCD的核心概念:将任务添加到队列
 5:OP的核心概念:将操作添加到队列
 6:op的使用步骤
    创建队列
    创建操作
    将操作添加到队列
 
 
 */

NSInvocationOperation

/*
 NSInvocationOperation:非常古老,ios2.0,开发中不用
 */
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self opDemo3];
}
-(void)opDemo3{
    for (int i= 0; i< 10; i++) {
        //创建队列:默认并发
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        //创建操作
        NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@(i)];
        //将操作添加到对象
        [queue addOperation:op];
    }
}
-(void)opDemo2{
    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    //创建操作
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"invocationOp"];
    //把操作添加到对象
    [queue addOperation:op];
}

-(void)opDemo1{
    //创建操作对象
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"invocation"];
    //调用start会在当前线程执行
    [op start];
    
}
 -(void)demo:(id)param{
     NSLog(@"%@--%@",param,[NSThread currentThread]);
 }

NSBlockOperation

@interface ViewController ()
//定义全局队列
@property (strong,nonatomic) NSOperationQueue *queue;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //实例化全局队列
    self.queue = [[NSOperationQueue alloc] init];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self OPDemo5];
}
#pragma mark - 线程间通信
-(void)OPDemo5{
    [self.queue addOperationWithBlock:^{
        NSLog(@"模拟下载..%@",[NSThread currentThread]);
        //如果异步任务执行后,拿到结果,就通知主线程刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"模拟刷新ui..%@",[NSThread currentThread]);
        }];
    }];
}

-(void)OPDemo4{
    //直接把操作添加到队列:无法拿到操作对象
    [self.queue addOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
}


-(void)OPDemo3{
    //创建队列:默认并发
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    for (int i = 0; i < 10;i++) {
        //创建操作
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
             NSLog(@"%zd - %@",i,[NSThread currentThread]);
        }];
        //把操作添加到队列
        [queue addOperation:op];
    }
}
-(void)OPDemo2{
    //创建队列:默认并发
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    //创建操作 默认异步
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"%@",[NSThread currentThread]);
    }];
    //将异步操作添加到并发队列
    [queue addOperation:op];
}
-(void)OPDemo1{
    //创建对象
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
    //调用start方法:依然在当前主线程执行
    [op start];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

NSOperation和GCD对比

GCD

  1. 核心概念:将任务添加到队列,并且指定任务执行的函数
  2. CGD是C语言的API
  3. ios 4.0推出的,针对多核处理器的并发技术
  4. 任务是封装在block中
  5. 要停止已经加入到队列的任务需要写复杂的代码
  6. 只能设置队列的优先级
  7. 建立任务间依赖关系比较复杂
  8. 高级功能
    阻塞barrier
    一次性once
    延迟操作after
    调度组group

NSOperation

  1. 核心思想: 把操作添加到队列
  2. OC框架,更加面向对象,是对GCD的封装
  3. ios2.0退出,苹果退出GCD之后,对NSOperation的底层全部重写
  4. 任务封装在operation对象中的,为我们提供了更多的选择,操作对象更加方便
  5. 可以取消掉队列中的任务,正在执行的任务除外
  6. 可以设置队列中的每一个操作的优先级
  7. 可以跨队列设置操作的依赖关系
  8. 高级功能
    最大操作并发数(GCD不好做)
    继续/暂停/全部取消
    跨队列设置操作的依赖关系

操作服务质量与监听操作执行结束

@interface ViewController ()

@property (nonatomic,strong) NSOperationQueue *queue;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.queue = [[NSOperationQueue alloc] init];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self opDemo];
}
-(void)opDemo{
    //操作1
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i =0; i < 5; i++) {
            NSLog(@"op1 %zd-%@",i,[NSThread currentThread]);
        }
    }];
    //设置op1的服务质量最高:服务质量等价于优先级,决定了队列里面的某些操作有更多的机会会被调用
    op1.qualityOfService = NSQualityOfServiceUserInteractive;
    //监听某个操作是否执行结束:一旦操作执行完毕,底层会自动回调completion
    void(^completionBlock)() = ^{
        NSLog(@"op1执行完了吗?%@",[NSThread currentThread]);
    };
    
//    //建议使用:更加简洁;今后如果给block的属性赋值,建议使用setter方法,block会自动补全
//    [op1 setCompletionBlock:^{
//        
//    }];
    op1.completionBlock = completionBlock;
    //把操作添加到队列
    [self.queue addOperation:op1];
    
    //操作2
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i =0; i < 5; i++) {
            NSLog(@"op2 %zd-%@",i,[NSThread currentThread]);
        }
    }];
    //op2的服务质量最低
    op2.qualityOfService = NSQualityOfServiceBackground;
    //把操作添加到队列
    [self.queue addOperation:op2];
    NSLog(@"------");
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

最大并发数

@interface ViewController ()
//队列
@property (nonatomic,strong) NSOperationQueue *queue;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //实例化队列
    self.queue = [[NSOperationQueue alloc] init];
    //设置队列最大并发数
    self.queue.maxConcurrentOperationCount = 2;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self opDemo];
}
-(void)opDemo{
    for (int i = 0; i < 20; i++) {
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            //模拟网络延迟:仅仅是为了放大队列最大并发数的执行的效果
            [NSThread sleepForTimeInterval:1.0];
            NSLog(@"%zd - %@",i,[NSThread currentThread]);
        }];
        [self.queue addOperation:op];

    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

队列的暂停继续和取消

@interface ViewController ()
//队列
@property (nonatomic,strong) NSOperationQueue *queue;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //实例化队列
    self.queue = [[NSOperationQueue alloc] init];
    //设置队列最大并发数
    self.queue.maxConcurrentOperationCount = 2;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self opDemo];
}
/*
 正在执行的操作无法取消
 如果你非要取消正在执行的操作,需要自定义NSOperation
 取消全部操作会有一定的时间延迟,具体延迟多久,是系统自己算的
 为什么会有延迟?
    队列一旦调用了cancelAllOperations,队列会遍历自己里面的所有操作
    每遍历出一个操作,就会调用cancle方法
    一旦操作对象调用了cancle方法,那么操作对象的canclled的属性就会被设置成YES,表示该操作不能正常执行
    一旦队列发现,操作对象的cancelled属性为YES了就不会调度其执行,会移除掉,operationCount不会对其记录
 */
#pragma mark - 取消
-(IBAction)cancelALL:(id)sender{
    //取消 /移除队列里面所有的操作
    [self.queue cancelAllOperations];
    NSLog(@"取消全部 %tu",self.queue.operationCount);
}
#pragma mark - 继续
-(IBAction)jixu:(id)sender{
    //使队列继续调度任务
    self.queue.suspended = NO;
    NSLog(@"继续 %tu",self.queue.operationCount);
}
#pragma mark - 暂停
/*
 正在执行的操作无法暂停
 operationCount:记录队列里面的操作个数,但是只会记录没有被队列调度的和调度了但是没有执行完的操作
 一旦先挂起队列,再添加操作到队列,这个操作是可以成功的添加进队列,但是无法被队列调度执行
 */
-(IBAction)zanting:(id)sender{
    //当队列里面没有操作时,不需要挂起队列
    if(self.queue.operationCount == 0){
        return;
    }
    //使队列暂停调度任务
    self.queue.suspended = YES;
    NSLog(@"暂停 %tu",self.queue.operationCount);
}

-(void)opDemo{
    for (int i = 0; i < 20; i++) {
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            //模拟网络延迟:仅仅是为了放大队列最大并发数的执行的效果
            [NSThread sleepForTimeInterval:1.0];
            NSLog(@"%zd - %@",i,[NSThread currentThread]);
        }];
        [self.queue addOperation:op];

    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

操作间的依赖

@interface ViewController ()
@property (nonatomic,strong) NSOperationQueue *queue;
@end
//需求:登录- 付费- 下载- 通知用户
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.queue = [[NSOperationQueue alloc] init];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self opDemo];
}
-(void)opDemo{
    //登录
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"登录 :%@",[NSThread currentThread]);
    }];
    //付费
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"付费 :%@",[NSThread currentThread]);
    }];
    //登录
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载 :%@",[NSThread currentThread]);
    }];
    //登录
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"通知用户 :%@",[NSThread currentThread]);
    }];
    //op4应该被添加到主队列:因为不能把同一个操作分别添加到两个队列
       //添加依赖关系
    
    /*
     一定要先建立依赖关系,再把操作添加到队列
     可以跨队列建立依赖关系
     不能建立循环依赖
     不能把同一个操作分别添加到两个队列
     */
    [op2 addDependency:op1];//付费依赖登录
    [op3 addDependency:op2];//下载依赖付费
    [op4 addDependency:op3];//通知用户依赖下载
    
    
    //批量把操作添加到队列
    //waitUntilFinished:不用等待前面的四个异步任务执行完,就可以执行后面的代码
    [self.queue addOperations:@[op1,op2,op3] waitUntilFinished:NO];
    
    [[NSOperationQueue mainQueue] addOperation:op4];
    

    NSLog(@"后面的代码");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
    
}


@end

相关文章

网友评论

      本文标题:多线程3

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