ios基础篇(十三)—— 调度组、NSOperationQueue

一、调度组

  • 有时候需要在多个异步任务都执行完成之后继续做某些事情,比如下载歌曲,等所有的歌曲都下载完毕之后 转到 主线程提示用户
//1 全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //2 调度组
    dispatch_group_t group = dispatch_group_create();
    //3 添加任务
    //把任务添加到队列,等任务执行完成之后通知调度组
    dispatch_group_async(group, queue, ^{
        NSLog(@"歌曲1  %@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"歌曲2  %@",[NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"歌曲3  %@",[NSThread currentThread]);
    });
    //4 所有任务都执行完成后,获得通知 (异步执行)
    //等调度组中队列的任务完成后,把block添加到指定的队列
//    dispatch_group_notify(group, queue, ^{
//        NSLog(@"okkkkkkk   %@",[NSThread currentThread]);
//    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//更新UI控件,提示用户
        NSLog(@"okkkkkkk   %@",[NSThread currentThread]);
    });
    NSLog(@"over");

调度组原理

在终端中 输入man dispatch_group_async
//1 全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 
    //2 调度组
    dispatch_group_t group = dispatch_group_create(); 
    //ARC中不用写
//    dispatch_retain(group);
    //3 进入调度组,执行此函数后,再添加的异步执行的block都会被group监听
    dispatch_group_enter(group);    
    //4 添加任务
    dispatch_async(queue, ^{
        NSLog(@"!!--!!");
        dispatch_group_leave(group);
        //ARC中此行不用写,也不能写
//        dispatch_release(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"!!------!!");
        dispatch_group_leave(group);
        //ARC中此行不用写,也不能写
        //dispatch_release(group);
    });
    
    //5  获得调度组的通知
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"okkkkkkk   %@",[NSThread currentThread]);
    });
//6 等待调度组 监听的队列中的所有任务全部执行完毕,才会执行后续代码,会阻塞线程(很少使用)
//下载三首歌曲,当歌曲都下载完毕 通知用户
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self demo2];
}
//调度组内部的原理
- (void)demo2 {
   //创建组
    dispatch_group_t group = dispatch_group_create();
    //创建队列
    dispatch_queue_t queue = dispatch_queue_create("hm", DISPATCH_QUEUE_CONCURRENT);   
    //任务1
    dispatch_group_enter(group);
    dispatch_async(queue, ^{     
        NSLog(@"任务1");
        dispatch_group_leave(group);
    });    
    //任务2
    dispatch_group_enter(group);
    dispatch_async(queue, ^{      
        NSLog(@"任务2");
        dispatch_group_leave(group);
    });
    
    //任务3
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2.0];
        NSLog(@"任务3");
        dispatch_group_leave(group);
    });   
    //等待组中的任务都执行完毕,才会执行
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"over");
    });
   
    //等待组中的任务都执行完毕,才会继续执行后续的代码
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    NSLog(@"hello ");
}
//演示调度组的基本使用
- (void)demo1 {
    //创建组
    dispatch_group_t group = dispatch_group_create();
    //队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //下载第一首歌曲
    dispatch_group_async(group, queue, ^{
        NSLog(@"正在下载第一个歌曲");

    });   
    //下载第二首歌曲
    dispatch_group_async(group, queue, ^{
        NSLog(@"正在下载第二个歌曲");
        [NSThread sleepForTimeInterval:2.0]; 
    });
    //下载第三首歌曲
    dispatch_group_async(group, queue, ^{
        NSLog(@"正在下载第三个歌曲");
    });   
    //当三个异步任务都执行完成,才执行
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"over %@",[NSThread currentThread]);
    });  
}

二、NSOperation

  • NSOperation的作用
    • 是OC语言中基于GCD的面向对象的封装
    • 使用起来比GCD更加简单(面向对象)
    • 提供了一些用GCD不好实现的功能
    • 苹果推荐使用,使用NSOperation不用关心线程以及线程的生命周期

  • 查看NSOperation的头文件
    • NSOperation是一个抽象类
      • 不能直接使用(方法没有实现)
      • 约束子类都具有共同的属性和方法
    • NSOperation的子类
      • NSInvocationOperation
      • NSBlockOperation
      • 自定义operation
  • NSOperationQueue队列

使用步骤

  • NSOperation和NSOperationQueue实现多线程的具体步骤
    1. 先将需要执行的操作封装到一个NSOperation对象中
    2. 然后将NSOperation对象添加到NSOperationQueue中
      • 系统会自动将NSOperationQueue中的NSOperation取出来
      • 将取出的NSOperation封装的操作放到一条新线程中执行

  • 建NSInvocationOperation对象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
  • 调用start方法开始执行操作
- (void)start;

一旦执行操作,就会调用target的sel方法

   注意

  1. 默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
  2. 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作。
  • 创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
  • 通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;

注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作

三、NSOperationQueue

  • NSOperationQueue的作用

NSOperation可以调用start方法来执行任务,但默认是同步执行的

如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作

  • 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
@interface ViewController ()
//全局队列
@property (nonatomic, strong) NSOperationQueue *queue;
@end

@implementation ViewController
//懒加载
- (NSOperationQueue *)queue {
    if (_queue == nil) {
        _queue = [[NSOperationQueue alloc] init];
    }
    return _queue;
}
//演示start
- (void)demo1 {
    //创建操作
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"hello %@",[NSThread currentThread]);
    }];
    //更新op的状态,执行main方法
    [op start];  //不会开新线程
}
//把操作添加到队列
- (void)demo2 {
    //创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    //创建操作
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"hello %@",[NSThread currentThread]);
    }];
    //把操作添加到队列中
    [queue addOperation:op];
}
- (void)demo3 {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    [queue addOperationWithBlock:^{
        NSLog(@"hello %@",[NSThread currentThread]);

    }];
}
//全局队列
- (void)demo4 {    
//    //并发队列,异步执行
//    for (int i = 0; i < 10; i++) {
//        [self.queue addOperationWithBlock:^{
//            NSLog(@"hello %d  %@",i,[NSThread currentThread]);
//        }];
//    }
}
// 操作的 completionBlock
- (void)demo5 {
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"hello %@",[NSThread currentThread]);
    }];
    //操作完成之后执行
    [op setCompletionBlock:^{
        NSLog(@"end %@",[NSThread currentThread]);

    }];    
    [self.queue addOperation:op];
}

四、线程间通信

  • 主队列
    • 添加到主队列的操作,最终都执行在主线程上
    • [NSOperationQueue mainQueue]
  • 当前队列
    • 获取当前操作所在的队列
    • [NSOperationQueue currentQueue]
  • 模拟当图片下载完成后回归到主线程上更新UI
@interface ViewController ()
//全局队列
@property (nonatomic, strong) NSOperationQueue *queue;
@end

@implementation ViewController
//懒加载
- (NSOperationQueue *)queue {
    if (_queue == nil) {
        _queue = [[NSOperationQueue alloc] init];
    }
    return _queue;
}
- (void)viewDidLoad {
    [super viewDidLoad];   
    [self.queue addOperationWithBlock:^{
      //异步下载图片
        NSLog(@"异步下载图片");        
        //获取当前队列
//        [NSOperationQueue currentQueue]       
        //线程间通信,回到主线程更新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"更新UI");
        }];
    }];
}
1 消息循环
    主线程的消息循环默认开启,子线程的消息循环默认不开启
2 消息循环的目的
    保证程序不退出
    负责处理输入事件
3 输入事件和消息循环的模式
    输入事件的模式必须跟当前消息循环的模式匹配,输入事件才会执行
4 子线程消息循环  run
5 GCD
    队列  串行队列 并行队列  全局(并行)队列 主队列
    任务
    执行  同步执行  异步执行
6 各种组合
    6.1 串行队列
        同步执行   不开线程,顺序执行
        异步执行   开一个线程,顺序执行
    6.2 并行队列(全局队列)
        同步执行   不开线程,顺序执行
        异步执行   开多个线程,无序执行
    6.3 主队列
        同步执行   在主线程上执行的话会死锁
        异步执行   主线程,顺序执行
7 Barrier 阻塞     多线程中操作线程不安全的类,要小心
8 after 延迟执行
9 once 一次性执行 线程安全的
    单例  保证一个程序中只有一份单例对象(工具类)
10 调度组 让多个异步任务 都完成之后做一件事情
11 NSOperation 抽象类  抽象类中的方法都没有实现,等待子类去实现(约束子类)
    NSInvocationOperation
    NSBlockOperation
        start 不开线程  会设置操作的状态  会调用main
        操作添加到队列 --  并行队列,异步执行  开多个线程,无序执行
12 NSOperationQueue

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值