使用GCD

介绍

  • 什么是 GCD

    全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”,纯C语言,提供了非常多强大的函数

  • GCD的优势

    GCD是苹果公司为多核的并行运算提出的解决方案

    GCD会自动利用更多的CPU内核(比如双核、四核)

    GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

    程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

  • 提示

    GCD存在于libdispatch.dylib这个库中,这个调度库包含了GCD的所有的东西,但任何IOS程序,默认就加载了这个库,在程序运行的过程中会动态的加载这个库,不需要我们手动导入。

    GCD是纯C语言的,因此我们在编写GCD相关代码的时候,面对的函数,而不是方法。

    GCD中的函数大多数都以dispatch开头。

任务和队列

  • GCD中有2个核心概念
    • 任务:执行什么操作
    • 队列:用来存放任务
  • GCD的使用就2个步骤
    • 定制任务
    • 确定想做的事情

将任务添加到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行

提示:任务的取出遵循队列的FIFO原则:先进先出,后进后出

执行任务

  • GCD中有2个用来执行任务的函数

    说明:把右边的参数(任务)提交给左边的参数(队列)进行执行。

    • 用同步的方式执行任务 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); queue:队列 block:任务
    • 用异步的方式执行任务 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
  • 同步和异步的区别

    • 同步:在当前线程中执行
    • 异步:在另一条线程中执行

队列

  • 队列的类型

    • 并发队列(Concurrent Dispatch Queue)

      可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效
      - 串行队列(Serial Dispatch Queue)

      让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

  • 补充说明

有4个术语比较容易混淆:同步、异步、并发、串行

同步和异步决定了要不要开启新的线程

同步:在当前线程中执行任务,不具备开启新线程的能力

异步:在新的线程中执行任务,具备开启新线程的能力

并发和串行决定了任务的执行方式

并发:多个任务并发(同时)执行

串行:一个任务执行完毕后,再执行下一个任务

  • 串行队列 GCD中获得串行有2种途径

    • 使用dispatch_queue_create函数创建串行队列

      dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); // 队列名称, 队列属性,一般用NULL即可

      示例:dispatch_queue_t queue = dispatch_queue_create("wendingding", NULL); // 创建

    • 使用主队列(跟主线程相关联的队列)

      主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行,使用dispatch_get_main_queue()获得主队列

      dispatch_queue_t queue = dispatch_get_main_queue();

  • 并发队列. GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建,使用dispatch_get_global_queue函数获得全局的并发队列

    dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此参数暂时无用,用0即可. 第一个参数为优先级,这里选择默认的。获取一个全局的默认优先级的并发队列。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列

    全局并发队列的优先级

    #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高

    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)

    #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低

  • 各种队列的执行效果


    4.png

block 的定义

block 的定义有点象函数指针,差别是用 ^ 替代了函数指针的 * 号,如下所示:

  • 无参数无返回值
//无参数,无返回值,声明和定义

void(^MyBlockOne)(void) = ^(void){

NSLog(@"无参数,无返回值");  

};  
MyBlockOne();//block的调用;
  • 有参数无返回值
//有参数,无返回值,声明和定义

void(^MyblockTwo)(int a) = ^(int a){

NSLog(@"@ = %d我就是block,有参数,无返回值",a);

  };  
MyblockTwo(100);
  • 有参数有返回值
//有参数,有返回值

int(^MyBlockThree)(int,int) = ^(int a,int b){    

  NSLog(@"%d我就是block,有参数,有返回值",a + b);returna + b; 

 };  
MyBlockThree(12,56);
  • 无参数有返回值(很少用到)
//无参数,有返回值

int(^MyblockFour)(void) = ^{NSLog(@"无参数,有返回值");
        return45;
  };
MyblockFour();
  • 实际开发中常用typedef 定义Block
typedef int (^MyBlock)(int , int);

@property (nonatomic,copy) MyBlock myBlockOne;
self.myBlockOne = ^int (int ,int){
    //TODO
}

系统提供的 dispatch 方法

为了方便地使用 GCD,苹果提供了一些方法方便我们将 block 放在主线程 或 后台线程执行,或者延后执行。

//  后台执行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
     // something
});

// 主线程执行:
dispatch_async(dispatch_get_main_queue(), ^{
     // something
});

// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // code to be executed once
});

// 延迟 2 秒执行:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // code to be executed on the main queue after delay
});

GCD 还有一些高级用法,例如让后台 2 个线程并行执行,然后等 2 个线程都结束后,再汇总执行结果。这个可以用 dispatch_group, dispatch_group_async 和 dispatch_group_notify 来实现. 线程分组

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
     // 并行执行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
     // 并行执行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
     // 汇总结果
});

后台运行

使用 block 的另一个用处是可以让程序在后台较长久的运行。在以前,当 app 被按 home 键退出后,app 仅有最多 5 秒钟的时候做一些保存或清理资源的工作。但是应用可以调用 UIApplication 的beginBackgroundTaskWithExpirationHandler方法,让 app 最多有 10 分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。

让程序在后台长久运行的示例代码如下:

// AppDelegate.h 文件
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
// AppDelegate.m 文件
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [self beingBackgroundUpdateTask];
    // 在这里加上你需要长久运行的代码
    [self endBackgroundUpdateTask];
}
- (void)beingBackgroundUpdateTask
{
    self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundUpdateTask];
    }];
}
- (void)endBackgroundUpdateTask
{
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
    self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}

你可能感兴趣的:(使用GCD)