GCD group 的使用

group 头文件中函数的解析:


/*
OS_OBJECT_DECL(dispatch_object);
#define DISPATCH_DECL(name)  OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
*/
// 从上面可以看出  dispatch_group 是  dispatch_object 子类
DISPATCH_DECL(dispatch_group);

dispatch_group_t ==  DISPATCH_DECL(dispatch_group);


/*
 创建一个组, 创建的组可能与 block 相关联。
 这个调度组能够被用来等待他引用的 block 的完成。
  - result : 一个新的组。 在失败的情况下返回 NULL
*/
dispatch_group_t
dispatch_group_create(void);


/**
调度组 在 queue 异步执行 block
*/
void
dispatch_group_async(
    dispatch_group_t group,            // 调度组对象
    dispatch_queue_t queue,            // 队列
    dispatch_block_t block             // block
);           

/**
调度组 在 queue 异步执行 函数
*/
void
dispatch_group_async_f(
    dispatch_group_t     group,          // 调度组对象
    dispatch_queue_t     queue,          // 队列
    void                 *context,       // 上下文(传递给函数的)
    dispatch_function_t  work            // 函数
);


long
dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

// 组中异步执行任务全部执行完成的通知
void
dispatch_group_notify(
    dispatch_group_t group,       // 队列组
    dispatch_queue_t queue,       // 执行任务的队列
    dispatch_block_t block);      // 任务 


// 组中异步执行的函数全部执行的通知
void
dispatch_group_notify_f(
    dispatch_group_t group,                  // 队列组
    dispatch_queue_t queue,                  // 执行任务的队列   
    void *context,                           // 上下文
    dispatch_function_t work);               // 函数

// 入组函数
void
dispatch_group_enter(dispatch_group_t group);

// 出组函数
void
dispatch_group_leave(dispatch_group_t group);

调度组在项目中的使用(调度组的基本使用)

调度组:
调度组是用来协调一个或多个任务提交到队列异步触发的。 应用程序可以使用调度组等待所有调度组中的所有任务的完成。

所有异步队列执行完毕后得到一个通知。
**场景: **
a 异步下载任务,b 异步下载任务, c 异步下载任务。
只有在 a, b, c 三个异步下载任务全部完成的情况下。才通知主线程刷新界面。亦可以通知某个队列执行其他的操作。

NSLog(@"before: %@", [NSThread currentThread]);

// 创建一个组 (获得一个新的,空的调度组)
dispatch_group_t g =  dispatch_group_create();

// 将队列关联组
dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
    NSLog(@"taskA: %@", [NSThread currentThread]);
});

// 将队列关联组
dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
    NSLog(@"taskB: %@", [NSThread currentThread]);
});

// 将队列关联组
dispatch_group_async(g, dispatch_get_global_queue(0, 0), ^{
    NSLog(@"taskC: %@", [NSThread currentThread]);
});

// 组中的队列全部执行完毕后就通知调度组
dispatch_group_notify(g, dispatch_get_main_queue(), ^{
    NSLog(@"MainTask: %@", [NSThread currentThread]);
});


 NSLog(@"after: %@", [NSThread currentThread]);


// 打印结果
2016-06-23 09:12:05.162 Thread-Objc[9371:984276] before: {number = 1, name = main}
2016-06-23 09:12:05.163 Thread-Objc[9371:984276] after: {number = 1, name = main}
2016-06-23 09:12:05.163 Thread-Objc[9371:984320] taskA: {number = 2, name = (null)}
2016-06-23 09:12:05.163 Thread-Objc[9371:984328] taskC: {number = 4, name = (null)}
2016-06-23 09:12:05.163 Thread-Objc[9371:984323] taskB: {number = 3, name = (null)}
2016-06-23 09:12:05.167 Thread-Objc[9371:984276] MainTask: {number = 1, name = main}

上面的代码是一个简单的使用方式。

调度组的使用的原理解析
打开终端输入

// 使用这个命令可以查看 GCD 的详细文档
$ man dispatch

// 查看和 group 相关的文档
$ man dispatch_group_create

文档示例
(官方文档的说明)

// dispatch_group_async() 函数的操作和下面是等价的:
The dispatch_group_async() convenience function behaves like so:

void
dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispat
ch_block_t block)
{
             // 引用计数器加1
             dispatch_retain(group);

            // 入组
             dispatch_group_enter(group);

            // 任务异步执行
             dispatch_async(queue, ^{

                      // 执行任务
                     block();

                     // 出组(通知组,任务执行完毕)
                     dispatch_group_leave(group);
                     
                     // 引用计数器减1 
                     dispatch_release(group);
        });
}

示例代码改写

NSLog(@"before: %@", [NSThread currentThread]);

dispatch_group_t g =  dispatch_group_create();


dispatch_group_enter(g);

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
    NSLog(@"taskA: %@", [NSThread currentThread]);
    
    dispatch_group_leave(g);
});



dispatch_group_enter(g);

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
    NSLog(@"taskB: %@", [NSThread currentThread]);
    
    dispatch_group_leave(g);
});



dispatch_group_enter(g);

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
    NSLog(@"taskC: %@", [NSThread currentThread]);
    
    dispatch_group_leave(g);
});


dispatch_group_notify(g, dispatch_get_main_queue(), ^{
    NSLog(@"MainTask: %@", [NSThread currentThread]);
});


NSLog(@"after: %@", [NSThread currentThread]);

// 打印结果
2016-06-23 09:35:52.744 Thread-Objc[9540:1004789] before: {number = 1, name = main}
2016-06-23 09:35:52.744 Thread-Objc[9540:1004789] after: {number = 1, name = main}
2016-06-23 09:35:52.745 Thread-Objc[9540:1004833] taskA: {number = 2, name = (null)}
2016-06-23 09:35:52.745 Thread-Objc[9540:1004829] taskC: {number = 3, name = (null)}
2016-06-23 09:35:52.745 Thread-Objc[9540:1004822] taskB: {number = 4, name = (null)}
2016-06-23 09:35:52.749 Thread-Objc[9540:1004789] MainTask: {number = 1, name = main}


/*
 dispatch_group_enter(g); 操作都在 g 所在线程。 
 即当前线程, 在进行异步操作之前, dispatch_group_enter(g) 都已经全部执行完毕。

 g 中已经完整的记录了 block 的个数。

 追踪 NSLog(@"after: %@", [NSThread currentThread]); 的打印可以知道。
 
 执行一次 dispatch_group_enter(g) 操作,block 在组中的记录就会 加 1 。
 在子线程中执行一次 dispatch_group_leave(g); 会使 block 在组中的记录就会 减 1 。
 
 当组中的 block 记录的值为 0 的时候,就会调用 dispatch_group_notify() 函数。
 
 */



理解上面的实例后,对于 GCD 中的组基本的学习已经差不多了


细节知识点说明:

dispatch_group_enter();dispatch_group_leave(); 必须成对使用。 这两个函数会更新 block 在组中的数量。

在这个示例中除了 dispatch_group_waitdispatch_group_async_f 基本都用了一遍。
dispatch_group_async_f 是函数调用的基本不用。

  • **dispatch_group_wait :
    ** 意思是等待 group 中所有的 block 都执行完毕触发这个函数,或者等待指定的时间完成后触发这个函数。这个指定的时间内group 变为空,这个函数将返回一个 0 ,表示成功。否则就是一个非空的值。当参数的值为 DISPATCH_TIME_FOREVER 的时候, 返回值总为空。
    注意:
    • 只有在所有的任务都添加到队列 才建议调用 dispatch_group_wait () 函数,如果后续还有新的 block 添加到 组中,请使用新的组。 ( 这个dispatch_group_wait () 还是必须在最后调用)
    • 只有在所有的任务都添加到队列 才建议调用 dispath_group_notify() 函数,如果后续还有新的 block 添加到 组中,请使用新的组。 ( 这个dispath_group_notify() 还是必须在最后调用)
  • dispatch_group_wait() 和 dispath_group_notify() 的 选择:
    dispatch_group_wait (DISPATCH_TIME_FOREVER) == dispath_group_notify()
    AFN 中的网络请求超时就是使用 dispatch_group_wait () 实现的。 当一个时间结束后自动返回一个超时错误。

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