GCD 中的 Block
在 GCD 中,可以使用 block.h
中的函数实现 block 的创建、执行和取消。
dispatch_block_t dispatch_block_create(dispatch_block_flags_t flags,
dispatch_block_t block);
该方法会根据提供的 block 以及 flags 标识,在堆上创建一个新的 block ,这个新的 block 可能会被 dispatch_async()
等相关方法添加到队列中去,也可能会被直接执行。
当 block 被提交到队列中时,其相关联的优先级不仅仅同其指定的 flags 值有关,也同其要加入的队列有关。
dispatch_block_flags_t
是 unsigned long
类型的枚举值,相关值如下:
名称 | 具体值 | 说明 |
---|---|---|
DISPATCH_BLOCK_BARRIER | 0x1 | 表示 block 被提交到并行队列中时,应作为分隔 block |
DISPATCH_BLOCK_DETACHED | 0x2 | 表示 block 被执行时,并不使用当前执行上下文中的参数,如果是直接执行,那么在执行体中,其将移除来自执行线程的属性参数; 如果是提交到了队列中,那么其将使用队列的参数及其本身的参数。 |
DISPATCH_BLOCK_ASSIGN_CURRENT | 0x4 | 表示在创建 block 时,当前上下文中的属性应传递给该 block ,若该 block 直接执行,那么在执行过程中,这些属性应当应用于执行线程中; 如果是提交到队列中,那么提交时刻的属性状态将替代 block 提交时的默认属性状态。 |
DISPATCH_BLOCK_NO_QOS_CLASS | 0x8 | 表示并不为 block 指定相关属性,如果是直接执行,那么使用执行线程的优先级属性; 如果是提交到队列,那么使用提交时的优先级属性。 |
DISPATCH_BLOCK_INHERIT_QOS_CLASS | 0x10 | 表示 block 被提交到队列中时,优先使用队列相关的优先级属性,除非队列并没有关联优先级。并且,该值是使用 dispatch_async() 函数添加 block 到队列中时的默认值。另外,如果同时传递了 DISPATCH_BLOCK_ENFORCE_QOS_CLASS 值,那么 DISPATCH_BLOCK_INHERIT_QOS_CLASS 将被忽略。 |
DISPATCH_BLOCK_ENFORCE_QOS_CLASS | 0x20 | 表示 block 被提交到队列中时,优先使用 block 相关联的优先级属性,只要其不会导致优先级的降低。并且该值是使用 dispatch_sync() 函数添加 block 到队列中或直接执行 block 时的默认值。 |
这些标识表示需要使用怎样的优先级,但是实际上 iOS 系统中有专门的类型来表示优先级的不同。
#if __has_include(<sys/qos.h>)
typedef qos_class_t dispatch_qos_class_t;
#else
typedef unsigned int dispatch_qos_class_t;
#endif
从该定义可知,在 qos.h
文件中存在 qos_class_t
的定义。
在线程的执行过程中,涉及到时延、CPU 、输入、输出以及网络访问等资源的使用,那么便需要一个变量来描述不同线程对这些资源的访问顺序。这个对线程资源访问先后的描述,也可以称作线程的优先级,但是这个优先级不能超过整个进程的优先级。
qos_class_t
是 unsigned int
类型的枚举值,其相关值如下:
名称 | 具体值 | 说明 |
---|---|---|
QOS_CLASS_USER_INTERACTIVE | 0x21 | 表示当前线程中的任务是与用户交互的,其权限高于系统中的其他任务,几乎拥有所有 CPU 及输入输出带宽资源,耗费电量较大,所以除了诸如手势事件、绘图、动画等与用户交互的任务,不宜使用该权限。 |
QOS_CLASS_USER_INITIATED | 0x19 | 表示当前线程中的任务是由用户触发的,并且用户正在等待任务处理结果。其权限低于用户交互任务权限,但是高于其他任务,并且不是高效能的,所以只适用于短期可得到执行结果的任务。 |
QOS_CLASS_DEFAULT | 0x15 | 表示系统默认的线程优先级类别,如 pthread_create() 创建的线程就默认使用该类别。其权限低于用户交互任务以及用户处罚任务的权限,但是高于公共任务及后台任务。 |
QOS_CLASS_UTILITY | 0x11 | 表示当前线程中的任务是普通任务,用户并不需要立即知道其执行结果,也不在意其执行过程,但其权限比系统维护的低级别任务较高,且执行过程是高效能的。 |
QOS_CLASS_BACKGROUND | 0x09 | 表示线程中的任务并不是用户触发的,而且用户可能也不需要知道执行结果,其权限比其他任务权限要低。 |
QOS_CLASS_UNSPECIFIED | 0x00 | 表示缺少或已经移除了优先级类别信息,作为 API 的返回值,可能表示线程属性配置同旧 API 不兼容或是同 QOS 类别系统相冲突。 |
在同一个优先级类别中,还有一个相对优先级的值,该值小于 0 并且大于 -15 ,包括 0 和 -15 ,这个相对值只在当前进程及相同类别中有意义。
#define QOS_MIN_RELATIVE_PRIORITY (-15)
通过下面两个方法可以获取当前线程以及主线程的优先级类别。
qos_class_t qos_class_self(void);
qos_class_t qos_class_main(void);
理解上面的枚举值,便可以理解下面这个 block 创建方法来。
dispatch_block_t dispatch_block_create_with_qos_class(dispatch_block_flags_t flags,
dispatch_qos_class_t qos_class,
int relative_priority,
dispatch_block_t block);
在创建 block 时,为其指定优先级权限类别以及相对权限。那么,block 具体执行时的权限则由 flags
和 qos_class
共同决定。
void dispatch_block_perform(dispatch_block_flags_t flags,
DISPATCH_NOESCAPE dispatch_block_t block);
根据指定的标识以及 block 创建一个新的 block 执行并释放,如同下面的代码:
dispatch_block_t b = dispatch_block_create(flags, block);
b();
Block_release(b);
应注意这个函数的执行是同步的。
long dispatch_block_wait(dispatch_block_t block, dispatch_time_t timeout);
同步等待指定的 block 执行完毕,或者超时。
void dispatch_block_notify(dispatch_block_t block,
dispatch_queue_t queue,
dispatch_block_t notification_block);
监听指定的 block ,当其执行完毕后,执行指定的 block 。
void dispatch_block_cancel(dispatch_block_t block);
取消指定 block 的执行,但是对于已经执行的 block 无效。