iOS学习篇之Grand Central Dispatch(GCD)
看官网文档时的简单记录,全文翻译可谓是漏斗百出,将就着理解一下吧。(*^__^*) 嘻嘻……
一些比较通俗易懂的文章推荐:
GCD (Grand Central Dispatch) 笔记、Grand Central Dispatch(GCD)、block && Grand Central Dispatch)
原文地址:Grand Central Dispatch (GCD) Reference
GCD包含语法特征(直译是语法特征/功能),运行时库和系统增强即提供系统、综合的改进方案来支持在iOS和Mac OS X上的多核CPU的并发编程。
BSD子系统、CoreFoundation和Cocoa API都已经被扩展支持这种改进来帮助系统和我们的应用程序促使它们运行的更加流畅,更加有效并加快响应速度。
想象一下对于独立的单应用程序来说有效的使用多核CPU是有多么的困难,更不用说在不同数量计算核心的不同计算机上或是在多个应用程序竞争这些CPU核心的环境下,在系统级别上操作,可以更加轻松方便的为这些运行着的应用程序调节和分配资源,为它们均衡的分配系统的可用资源。
本文档描述了GCD的API,这些API支持在Unix系统层级上执行异步操作,你可以使用这些API来管理文件描述符,Mach端口,信号和计时器。在OS X 10.7及之后的版本,你也可以使用GCD来处理通用异步I/O操作的文件描述符。
GCD没有被限制说只能是系统层级的应用程序上可以使用,但是在你在更高级别的程序上使用之前,你应该考虑一下是否可以使用系统给你提供的具有类似功能的Cocoa API(通过NSOperation和block对象),这些API将更易使用,或许更适合你的需求。查看Concurrency Programming Guide了解更多。
重要:当fork系统调用时混合使用GCD时要注意,如果一个进程在调用fork之前调用了GCD,在一个成功的exec指令或一个相关的功能完成之后,在结果子进程中添加额外的GCD将是不安全的。(翻译的太绕口了,能力有限,请谅解啊!还是建议你们直接看英文文档。)
GCD对象和自动引用计算:
当你使用OC编译器来编译你的APP(应用程序都称作APP了)时,所有被调度的对象就都是OC对象,这种情况下,当自动引用计算(ARC)启用时,调度的对象将被自动保持和释放,就像其他任何的OC对象一样。当ARC禁用时,使用 dispatch_retain 和 dispatch_release 方法(或者OC语义)来保持和释放你的调度对象。你不能使用Core Foundation的retain/release方法。
如果你想要在一个ARC启用的APP中(比如你的程序代码比较古老,当前XCode的SDK版本却又比较高的情况)使用retain/release语义(方法),你通过为你的编译环境添加-DOS_OBJECT_USE_OBJC=0标识来禁用OC的对象机制。
功能:
创建和管理队列
(1) dispatch_get_main_queue
- 返回与应用程序主线程相关联的串行调度队列。
【描述】
dispatch_queue_t dispatch_get_main_queue(void);
【返回值】
返回主线程队列。这个队列在main函数被调用之前就被自动创建了,用以支持维护主线程。
【讨论】
主队列是系统自动创建的并和主线程相关联的。你的APP通过下面三种途径中的其中一种来调用block提交到主队列中去。
*调用dispatch_main
*调用 UIApplicationMain (iOS) 。
*在主线程中使用一个 CFRunLoopRef 。
和全局并行队列一样,调用dispatch_suspend,dispatch_resume,dispatch_set_context,并且当通过这些方法使用这个队列时,像是没有效果的。(这个实在是翻译不过来啊,大家看原文吧!尴尬!)
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上版本可用
(2) dispatch_get_global_queue
- 返回系统定义的全局并行队列,该方法有一个参数用来指定这个队列的能力。
【描述】
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
【参数】
identifier: 翻译太绕口了,说的通俗易懂一点就是优先级,跟线程的优先级类似,具有以下几个类值:QOS_CLASS_USER_INTERACTIVE,QOS_CLASS_USER_INITIATED,QOS_CLASS_UTILITY或QOS_CLASS_BACKGROUND。
这几个值分别指定了不同的优先级,其中处理用户交互或处理用户触发的任务比那些后台任务具有更高的优先级。
你也可以从 dispatch_queue_priority_t 中选择一个值来指定队列的优先级,这些值对应着几个指定的类。
flags: 这个参数目前没有用处,是为将来备用的参数,值为0。
【返回值】
你所请求(跟你的传入的参数有关系啦,就是我上面说过的)的全局并行队列。
【讨论】
这个方法根据你传入的参数返回适合你的队列,调用dispatch_suspend,dispatch_resume和dispatch_set_context方法对本方法的返回值无影响。
相对于其他队列,被丢进本队列中的任务是并行执行的。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上版本可用
(3) dispatch_queue_create
- 创建一个可以将block代码块提交给它的新的队列。
【描述】
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
【参数】
label: 一个字符串,用来标识这个新创建的队列,跟JAVA中的线程名称差不多一个意思,这样方便我们在Debug调试的时候可以查看到底是哪些线程在执行任务,比如在Instuments中调试。
因为APP,第三方库和系统框架层都可以创建它们自己的队列,因此推荐这个名称是一个反向的DNS名称样式(例如com.example.muqueue)。当然本参数是可选的,也可以传NULL。
attr: 在OS X 10.7及之后以及iOS 4.3及之后的版本中,可以指定DISPATCH_QUEUE_SERIAL(或者NULL)来创建一个连续(非并发)的队列,或者指定DISPATCH_QUEUE_CONCURRENT来创建一个并行队列。在更早的版本中,你只能传入NULL作为参数。
【返回值】
新创建的队列
【讨论】
被提交到连续队列的block任务总是按照FIFO(先进先出)的规则且在同一时间只有一个执行。注意,然而,被提交到这些独立的队列中的block相对于其他的队列来说有可能是并行的执行。被提交到并行队列中的block也是按照FIFO的原则被取出的,但是如果资源允许(即内存充足)它们将被并发的运行。
当你的APP不再需要使用这些队列来提交相关任务时,这些队列应该通过调用dispatch_release方法被释放。
被提交给队列的block都持有对本队列的引用,因此只有当全部的block任务都被执行完毕时,这个队列才会被回收。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上版本可用
(4) dispatch_get_current_queue (iOS 6.0中被弃用了)
- 返回当前block所在的队列。
【描述】
dispatch_queue_t dispatch_get_current_queue(void);
【返回值】
返回当前队列
【讨论】
这个方法被定义为绝不返回NULL。
当从一个被提交给队列的block之外的某个地方调用本方法时,如果本方法在主线程中执行,那么将返回主队列,如果从其他线程中执行,那么将返回程序默认的并行队列。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上版本可用
在iOS6.0中被弃用了
(5) dispatch_queue_attr_make_with_qos_class
- 返回通过指定服务质量信息创建的队列的属性信息
【描述】
dispatch_queue_attr_t dispatch_queue_attr_make_with_qos_class (dispatch_queue_attr_t attire, dispatch_qos_class_t qos_class, int relative_priority);
【参数】
attr: 与特定的服务质量类相关联的队列的属性值信息。如果你想让被提交的任务被连续的执行,则指定DISPATCH_QUEUE_SERIAL值,或如果你想让被提交的任务被并发的执行,则指定DISPATCH_QUEUE_CONCURRENT值。如果你传NULL,则此方法默认创建一个连续的队列。
qos_class: 指定你的队列的服务质量的类值。这个上面说明过了,请查看第(2)条对dispatch_get_global_queue的介绍。
relative_priority: 一个负数,对那四个特定的服务质量优先级所代表的值的一个偏移,这个值必须小于0并且大于MIN_QOS_CLASS_PRIORITY。
【返回值】
一个属性值,如可被传入 dispatch_queue_create 方法作为参数创建一个队列
【讨论】
当你想要通过 dispatch_queue_create 方法创建一个你指定了服务质量的队列的时候,应该先调用一次本方法。本方法通过联合由你所指定的服务质量信息相关联的队列类型属性和返回一个你可传入 dispatch_queue_create 作为参数的值。使用本方法时,你所指定的服务质量的值优先于本队列本身内嵌的优先级。(翻译的优点狗血!大家自己看原文吧。)
全局队列的优先级与服务质量类的对应关系如下:
* DISPATCH_QUEUE_PRIORITY_HIGH 对应于 QOS_CLASS_USER_INITIATED 类。
* DISPATCH_QUEUE_PRIORITY_DEFAULT 对应于 QOS_CLASS_UTILITY 类。
* DISPATCH_QUEUE_PRIORITY_LOW 对应于 QOS_CLASS_UTILITY 类附带一个-8的偏移。
* DISPATCH_QUEUE_PRIORITY_BACKGROUND 对应于 QOS_CLASS_BACKGROUND 类。
【重要声明】
@import Dispatch
【有效性】
在iOS 8.0及以上版本可用
(6) dispatch_queue_get_label
- 当创建队列时指定的标签信息,即类似JAVA中的线程名称
【描述】
const char * dispatch_queue_get_label( dispatch_queue_t queue );
【参数】
queue: 参数不能为NULL。
【返回值】
队列的标签。结果有可能是NULL,如果创建队列的时候没有指定的话。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上可用
(7) dispatch_set_target_queue
- 为给定的对象绑定一个目标队列
【描述】
void dispatch_set_target_queue( dispatch_object_t object, dispatch_queue_t queue );
【参数】
object: 要修改的对象。这个参数不能为NULL。
queue: 为这个对象设置一个新的目标队列。这个新的队列被retain保持,计数加1,并且如果这个对象之前绑定过另外一个队列,将被release释放。这个参数不能为NULL。
【讨论】
一个对象的目标队列是负责处理这个对象的。这个目标队列决定了这个对象最终被调用时所在的队列?(不知道是不是这个意思!)。另外,修改一些对象的目标队列会修改它们的行为:
* 分发调度队列:
一个分发队列的优先级是继承自其目标队列的。使用 dispatch_get_global_queue 方法来为你所期望的优先级获得一个合适的目标队列。
如果你提交一个block到一个连续队列,并且这个连续队列的目标队列是一个不同的连续队列,则这个block不会与被提交到这个目标队列或是其他与其有相同目标队列的队列中的其他block并发执行。
【重要】
如果你修改一个队列的目标队列,你必须要避免创建了一个循环的继承关系,导致类似死循环。
* 分发调度资源:
一个调度资源的目标队列指定了事件处理和取消处理的block被提交到哪里。
* 分发调度 I/O 通道:
一个调度I/O通道的目标队列指定了这些I/O处理操作将在哪里执行。这可能会影响处理I/O操作的优先级。比如,如果通道的目标队列的优先级被设置为DISPATCH_QUEUE_PRIORITY_BACKGROUND,那在本队列中通过 dispatch_io_read 或 dispatch_io_write 执行的任何I/O操作,当I/O资源处于争夺状态(即可能好多线程都有在读写)时将被压制,优先级较低。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上可用
(8) diaptch_main
- 执行已经被提交到主队列中的block任务们(复数)
【描述】
void dispatch_main( void );
【返回值】
无返回值
【讨论】
((This function "parks" the main thread)这句话没法翻译啊!)和等待block被提交到主队列中。在主线程中调用UIApplicationMain(iOS),NSApplicationMain(OS X)或者CFRunLoopRun的应用程序不能调用dispatch_main。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上可用
队列中的任务的调度
GCD为应用程序提供和管理FIFO队列让你的程序可以以block对象的形式来提交你的任务。block提交给调度队列的任务在一个完全由系统管理的线程池中执行。无法保证哪个任务在哪个线程中执行。GCD提供三种类型的队列:
* Main主队列:任务在你的应用程序主线程中被挨个连续的执行。
* Concurrent并发队列:任务被按照FIFO的原则进行取出,但是却可以并发的运行着并可以任何顺序完成。
* Serial连续队列:按照FIFO原则取出并挨个执行,一次执行一个任务。
这个主队列由系统自动创建并和应用程序的主线程相关联。你的APP使用下面三种方法中的任意一种(只能是一种)来调用提交到主队列中的block。
* 调用 dispatch_main 方法。
* 调用UIApplicationMain(iOS)或NSApplicationMain(OS X)。
* 在主线程中调用CFRunLoopRef。
使用并发队列来并发的执行大量的任务。GCD会为你的应用程序自动的创建四个并发的全局调度队列(在iOS 5和OS X v10.7之前是三个),它们之间的唯一区别便是它们本身的优先级。你的APP可以通过 diapatch_get_global_queu 方法来请求这些队列。因为这些并发队列对你的APP来说是全局的,你无需对它们进行 retain 或者 release 操作。即使你对它们调用了这两个方法,也会被忽略。在OS X v10.7及以上或者iOS 4.3及以上,你也可以在你的代码模块中创建额外的并发队列来使用。
使用连续队列(串行队列)来保证你的任务按照可预见的顺序来执行。这也是识别出一个具有特别目的的串行队列的最佳实践,比如保护一个资源或同步的关键过程。你的APP必须明确的创建和管理串行队列。如果有必要,你可以任意的创建它们,但是你应该避免使用它们来代替并发队列而只是为了同时地执行这些任务。
【重要】
GCD是C语言级别的API;它不能像高级语言一样具备捕获异常的能力。你的APP必须在提交到队列中执行任务的block返回之前捕获所有异常。
dispatch_async
- 提交一个block到队列中,异步执行,方法会立刻放回。
【描述】
void dispatch_async( dispatch_queue_t queue, dispatch_block_t block );
【参数】
queue : 将block提交给它的某个队列。这个队列会被系统自动 retain 直到这个block被执行完毕。这个参数不能为NULL。
block : 提交到目标队列的block。这个方法会为调用者执行 Block_copy 和 Block_release 方法来维护。这个参数不能为NULL。
【讨论】
这个方法是将一个block提交到队列的最基本的机制(原理)。调用此方法时,在block被提交上去之后这个方法将立即返回,从不会去等待这个block被调用。相当于其他提交到本队列中的block,本队列直接决定了这个block将以串行还是并发的方式执行。无关联的、独立的的串行队列相对于其他的串行队列处理其中的block可以看做是并发的。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0及以上版本可用
dispatch_async_f
- 提交一个APP内定义的方法到队列中异步的执行,方法立即返回。
【描述】
void dispatch_async_f ( dispatch_queue_t queue, void *context, dispatch_function_t work );
【参数】
queue:将block提交给它的某个队列。这个队列会被系统自动 retain 直到这个block被执行完毕。这个参数不能为NULL。
context:由APP定义,将被提交到待执行方法作为参数。
work:提交到目标队列待执行的方法。传递到方法的第一个参数是 context 参数。这个参数不能为NULL。
【讨论】
这个方法是将一个由程序定义的方法提交到队列的最基本的机制(原理)。调用此方法时,在block被提交上去之后这个方法将立即返回,从不会去等待这个block被调用。相当于其他提交到本队列中的block,本队列直接决定了这个block将以串行还是并发的方式执行。无关联的、独立的的串行队列相对于其他的串行队列处理其中的block可以看做是并发的。
【重要声明】
@import Dispatch
【有效性】
在iOS 4.0 及以上版本可用。
dispatch_sync
- 提交一个block对象到一个队列中执行并且等待这个block被执行完毕。
【描述】
void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block );
【参数】
queue:将block提交给它的某个队列。这个参数不能为NULL。
block:提交到目标队列的block。这个参数不能为NULL。
【讨论】
提交一个block到队列中同步的执行。不像 dispatch_async 方法,这个方法不会立即返回,而是等待这个block被执行完。调用本方法并以死锁的方式锁住当前队列的结果。(有翻译的不恰当的地方还望指出并修正,多谢!)
不像 dispatch_async 方法,不会在目标队列中执行 retain 方法。因为调用本方法是同步的,它会“借用”调用者的引用。此外,不会对block执行Block_copy。
作为一种优化,这个方法有可能会在当前线程中调用block。
【有效性】
在iOS 4.0及以上版本可用。
dispatch_sync_f
- 与 dispatch_async 的对应方法 dispatch_async_f 方法的解释差不多,这里不做重复的赘述了。
dispatch_after
- 在指定的时间执行这个block。
【描述】
void dispatch_after ( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block );
【参数】
when:通过调用 dispatch_time 或者 dispatch_walltime 返回的时间点。
queue:将block提交给它的某个队列。这个队列会被系统自动 retain 直到这个block被执行完毕。这个参数不能为NULL。
block:被提交上的block。这个方法会为调用者执行 Block_copy 和 Block_release 方法来维护。这个参数不能为NULL。
【讨论】
这个方法将一直等待到指定的时间,然后被异步的添加到指定的queue中去执行。
传入 DISPATCH_TIME_NOW 作为 when 的参数是被支持的,但这不是作为替换调用 dispatch_async 方法的最佳方案。传入 DIAPATCH_TIME_FOREVER 暂未被定义和支持。
【有效性】
在 iOS 4.0及以上可用。
dispatch_after_f
- 在指定的时间执行这个程序定义的方法。
【描述】
void dispatch_after_f ( dispatch_time_t when, dispatch_queue_t queue, void *context, disptch_function_t work );
【参数】
参数的描述在上面的几个方法中已经做过描述了,参考 dispatch_async_f 等,这里不做重复的赘述了。
【讨论】
与 dispatch_after 的讨论类似。
【有效性】
在 iOS 4.0及以上可用。
dispatch_apply
- 提交一个block到队列中,多次调用。
【描述】
void dispatch_apply ( size_t iterations, dispatch_queue_t queue, void (^block)(size_t) );
【参数】
iterations:执行的次数。
queue:将block提交给它的某个队列。这个参数不能为NULL。
block:由程序定义的待提交的方法。这个参数不能为NULL。
【讨论】
这个方法用来提交一个block给队列多次调用重复执行,并等待任务的所有循环被执行完毕后返回。如果这个目标队列是由 dispatch_get_global_queue 方法返回的一个并发队列,那block将被并发的执行,并且它将因此而“折返安全”。
配合一个并发队列来使用本方法作为一个高效并发的循环来说将是很有用的。
循环的当前索引总是会被传入到每次调用的block的参数中。
【有效性】
在 iOS 4.0及以上可用。
dispatch_apply_f
- 提交一个程序定义的方法到队列中,多次调用。
【描述】
void dispatch_apply_f ( size_t iterations, dispatch_queue_t queue, void *context, void (*work)(void *, size_t) );
【参数】
iterations:执行的次数。
queue:将block提交给它的某个队列。这个参数不能为NULL。
context:由APP定义,将被提交到待执行方法作为参数。
work:提交到目标队列待执行的方法。传递到方法的第一个参数是 context 参数(指针类型,第二个参数是循环的当前索引,这个参数不能为NULL。
【讨论】
与 dispatch_apply 类似。
【有效性】
在 iOS 4.0及以上可用。
dispatch_once
- 执行一次该block对象,并且在整个程序的生命周期内只执行这么一次。(常被用来在单例模式中使用,创建单例对象)
【描述】
void dispatch_once ( dispatch_once_t *predicate, dispatch_block_t block );
【参数】
predicate:一个指向 dispatch_once_t 的指针,被用来测试这个block是否被执行完毕。
block:等待被执行的block对象。
【讨论】
这个方法对于应用程序中的全局数据(例如单例)的初始化非常有用。应总是在使用或者测试任何通过这个block初始化的变量之前调用本方法。
如果在多线程环境中同时被调用,这个方法将被同步等待直到这个block被执行完成。(总之,是写单例的好方法啊!)
这个 predicate 参数必须被指向一个存储在全局或static静态作用域中的变量。使用这个 predicate 自动或动态存储(包括OC实例变量)的结果未被定义。
【有效性】
在 iOS 4.0及以上可用。
dispatch_once_f
- 与 dispatch_once 类似,并可参照上述其他方法的解释来理解本方法。
使用调度组
组块允许组合的同步。(自己理解吧,好绕啊!)。你的APP可以提交多个block并跟踪它们的完成,甚至于它们在不同的队列中执行时。这种机制将非常有用,当程序必须等待其他所有指定的任务完成之后才可继续执行时。
dispatch_group_async
- 提交一个block到某队列中,并于指定的调度组关联起来。
【描述】
void dispatch_group_async ( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block );
【参数】
group:与提交上来的block相关联的调度组。这个调度组将被系统 retain 直到这个block被执行完成。这个参数不能为NULL。
queue:将block提交给它并异步调用的一个队列。这个队列将被系统 retain 直到这个block被执行完成。这个参数不能为NULL。
block:被异步执行的block。这个方法会为调用者执行 Block_copy 和 Block_release 方法来维护。这个参数不能为NULL。
【讨论】
提交一个block给某个队列,并与给定的调度组相关联。这个调度组可以用来等待被它本身所持有的所有block执行完毕。
【有效性】
在 iOS 4.0及以上可用。
dispatch_group_async_f
- 与dispatch_group_async 类似,并可参照上述其他方法的解释来理解本方法。
dispatch_group_create
- 创建一个block可关联的新的组。
【描述】
dispatch_group_t dispatch_group_create ( void );
【返回值】
新创建的组,或失败时返回的NULL。
【讨论】
这个方法创建一个新的组供block关联(在 dispatch_group_async 方法中作为参数使用的组)。这个调度组持有一个对未完成关联任务的计数,当有新的任务被关联时计数加1,当任务结束时相应的,计数减1。诸如 dispatch_group_notify 和 dispatch_group_wait 方法使用这个计数,允许你的程序来决定所有与本组关联的任务在什么时候结束。到那时,你的程序便可以采取任何适当的行动。
当你的程序不再需要这个调度组时,应该调用 dispatch_release 来释放对这个调度组对象的引用并最终释放它所占据的内存。
【有效性】
在 iOS 4.0及以上可用。
dispatch_group_enter
- 明确指示一个新的block进入到了调度组。
【描述】
void dispatch_group_enter ( dispatch_group_t group );
【参数】
group:被更新的调度组。参数不能为NULL。
【讨论】
调用本方法将增加本组对当前未完成任务的计数(+1)。使用这个方法(还有 dispatch_group_leave)允许你的程序当通过其他手段而不是通过 dispatch_group_async 方法明确的从组中添加和删除任务时正确的管理你的任务引用计数。调用这个函数必须与调用 dispatch_group_leave 平衡。你可以使用这个方法来将一个block同时和不止一个组进行关联。
【有效性】
在 iOS 4.0及以上可用。
dispatch_group_leave
- 明确指示一个在调度组中的block执行完成了。
【描述】
void dispatch_group_leave ( dispatch_group_t group );
【参数】
group:被更新的调度组。参数不能为NULL。
【讨论】
调用本方法将增加本组对当前未完成任务的计数(+1)。使用这个方法(还有 dispatch_group_leave)允许你的程序当通过其他手段而不是通过 dispatch_group_async 方法明确的从组中添加和删除任务时正确的管理你的任务引用计数。
调用这个函数必须与调用 dispatch_group_leave 平衡。如果调用它的次数多于 dispatch_group_enter将是无效的,会导致一个负的计数。
【有效性】
在 iOS 4.0及以上可用。
dispatch_group_notify
- 执行一个提交到队列中的block,当在此之前被提交到组中的其他block任务被执行完成时。
【描述】
void dispatch_group_notify ( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block );
【参数】
group:观察着任务执行动态的组。这个调度组将被系统 retain 直到这个block被执行完成。这个参数不能为NULL。
queue:当组内任务执行完成时这个被支持的block被提交上去的队列。这个队列将被系统 retain 直到这个block被执行完成。这个参数不能为NULL。
block:当组内任务执行完成时被提交上去的block。这个方法会为调用者执行 Block_copy 和 Block_release 方法来维护。这个参数不能为NULL。
【讨论】
这个方法将在所有与调度组相关联的block都被执行完成时执行这个被提交到指定队列中去、就像是被通知一样的block。如果这个组是空的(没有block任务与此组相关联),那么这个block对象将被立即提交。
当这个block被提交上去后,组是空的。此时,这个组可通过调用 dispatch_release 被释放,也可以通过添加新的block而被重新使用。查看 dispatch_group_async 了解更多信息。
【有效性】
在 iOS 4.0及以上可用。
管理调度对象
GCD提供调度对象接口允许你的程序来管理诸如处理内存管理、暂停和恢复执行、定义对象环境和打印任务数据等方面。调度对象必须手动的持有retain和释放release并不被内存回收。
dispatch_debug (iOS 6.0中弃用了)
- 暂时跳过,不做翻译。
dispatch_get_context
- 返回一个对象的由程序定义的上下文环境对象。
【描述】
void * dispatch_get_context ( dispatch_object_t object );
【参数】
object:这个参数不能为NULL。
【讨论】
你的程序可以使用一个对象来关联自定义的上下文数据,只被你的程序使用。你的程序必须适当的分配和释放这个数据。
【有效性】
在 iOS 4.0及以上可用。
dispatch_release
- 对调度对象的引用计数做减1操作。
【描述】
void dispatch_release ( dispatch_object_t object );
【参数】
object:被release的对象。这个参数不能为NULL。
【讨论】
一个对象,一旦所有指向它的引用都被释放(引用计数为0时),它将被异步的释放掉。当你的程序不再需要一个被创建的对象时,应该调用这个方法来释放对它的兴趣(是引用的意思吧)并允许在适当的时候释放它的内存。请注意,GCD无法保证这个给定的对象具有最后或是唯一的指向这个给定对象的引用。
【重要】
如果你的程序被编译用于部署到OS X v10.8及之后或iOS v6.0及之后的版本,调度队列的管理方式属于典型的ARC,因此你无需 retain 或 release 这个调度队列。
为了兼容现有代码,这个行为是可配置的。查看 Dispatch Queues and Automatic Reference Counting (Dispatch Queues and Automatic Reference Counting)查看更多。
【有效性】
在 iOS 4.0及以上可用。
dispatch_resume
- 在调度对象上恢复block对象的调用。
【描述】
void dispatch_resume ( dispatch_object_t object );
【参数】
object:被恢复的对象。这个参数不能为NULL。
【讨论】
调用这个方法将递减对一个挂起的调度队列或调度事件资源对象的挂起计数。然而这个计数大于0,这个对象始终是被挂起的。当这个挂起计数变成0时,任何提交到这个调度队列的block任务或任何在挂起期间由调度资源观察到的任何事件都将被启动。
有一个例外,每次对dispatch_resume的调用必须于dispatch_suspend的调用保持平衡。由 dispatch_source_create 创建并返回的新的调度事件资源对象有一个计数为1的挂起计数,并且必须在任何事件启动之前被唤醒恢复。这个方法允许你的程序在交付第一个事件之前完全的配置这个调度事件资源对象。在所有其他情况下,调用 dispatch_resume 的次数超过 dispatch_suspend 时将导致一个负的挂起计数是没有定义的。
【有效性】
在 iOS 4.0及以上可用。
dispatch_retain
- 递增调度对象的引用计数。
【描述】
void dispatch_retain ( dispatch_object_t object );
【参数】
object:被retain的对象。这个参数不能为NULL。
【讨论】
调用本方法必须与调用 dispatch_release 方法保持平衡。如果你的程序的多个子系统共享一个调度对象,每个子系统都应该调用 dispatch_retain 注册,表示对该对象的引用兴趣。这个对象只有在所有的子系统对其实现了兴趣,释放对它的引用时才会被释放。
注意,你的程序不需要 retain 或 release 全局(main主队列和concurrent并发队列,在上面提到过。)的调度队列。
【重要】
如果你的程序被编译用于部署到OS X v10.8及之后或iOS v6.0及之后的版本,调度队列的管理方式属于典型的ARC,因此你无需 retain 或 release 这个调度队列。
为了兼容现有代码,这个行为是可配置的。查看 Dispatch Queues and Automatic Reference Counting (Dispatch Queues and Automatic Reference Counting)查看更多。
【有效性】
在 iOS 4.0及以上可用。
dispatch_set_context
- 为一个对象关联一个由程序定义的上下文环境。
【描述】
void dispatch_set_context ( dispatch_object_t object, void *context );
【参数】
object:这个参数不能为NULL。
context:与这个object对象新关联的程序定义的上下文环境。这个参数可以为NULL。
【讨论】
你的程序可以自定义上下文数据和对象进行关联,只供你的程序使用。你的程序必须适当的分配和释放这个数据。
【有效性】
在 iOS 4.0及以上可用。
使用信号灯 ?
- 暂时不做翻译。
使用屏障
一个调度屏障允许你在一个并发调度队列中创建一个同步的点。当遇到一个屏障,并发队列延迟对屏障block(或是任何未来的block)的执行,直到这个屏障被执行完成之前所有的block被提交上去。在同步点时,这个屏障block执行本身。在此之后,这个队列恢复它自己的正常的执行行为。
dispatch_barrier_async
- 提交一个屏障block异步执行并立即返回。
【描述】
void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );
【参数】
queue:用来执行这个屏障block的队列。这个队列将被系统 retain 直到这个block被执行完成。这个参数不能为NULL。
block:要提交给目标队列的屏障block。这个block是被复制的并且被 retain 持有直到它完成执行时,在那个点时,它被释放。这个参数不能为NULL。
【讨论】
调用本方法总是会在block被提交上去之后立即返回,从不会等待block被执行。当屏障block到达私有并发队列的前面时,并不会立即执行。取而代之的是,这个队列会一直等待直到当前的执行块执行完成。在那个时候,屏障block执行本身。任何在此屏障block之后提交的block在此屏障block执行完成之前都不会被执行。
你指定的这个队列必须是你通过 dispatch_queue_create 方法创建的并发队列。如果你传入本方法的队列参数是一个串行队列或是全局队列中的一个,那么本方法的行为将类似于 dispatch_async 方法。
【有效性】
在iOS 4.3 及以上版本可用。
dispatch_barrier_async_f
- 提交一个屏障方法异步执行并立即方法。
【描述】
void dispatch_barrier_async_f ( dispatch_queue_t queue, void *context, dispatch_function_t work );
【参数】
参考上面的解释,基本一样的解释。
【讨论】
参考dispatch_barrier_async的解释,基本一样的解释。
【有效性】
在iOS 4.3 及以上版本可用。
dispatch_barrier_sync
- 与 dispatch_barrier_async 类似,那个是异步,这个是同步。
【讨论】
不像 dispatch_barrier_async ,在目标队列中不会执行 retain 操作。因为调用本方法是同步的,它只是“借用”调用者的引用。此外,block也不会调用Block_copy方法。
作为优化,这个方法有可能会在当前线程中调用这个屏障block。
【有效性】
在iOS 4.3 及以上版本可用。
dispatch_barrier_sync_f
- 不在赘述。
使用调度I/O便利的API接口
方便的调度I/OAPI接口让你可以异步的在文件描述符上执行读取和写入操作。这个API支持以基于流的语义的方式来访问文件的内容。
dispatch_read
- 使用这个特殊的文件描述符来异步的执行读取的操作。
【描述】
void dispatch_read ( dispatch_fd_t fd, size_t length, dispatch_queue_t queue, void (^handler)(dispatch_data_t data, int error) );
【参数】
fd:描述要读取的文件数据的源。
length:读取的文件数据的最大长度。
queue:执行这个指定的handler块的队列。
handler:当指定的数据被读取或错误发生时被调用的blcok块。这个handler块的参数解释如下:
- data:从文件中读取出的数据。这个对象会尽可能多的从文件中读取足够的有效的数据,直到能达到指定的length个数据长度。这个data数据对象被系统持有,且在handler返回时被释放。如果你希望继续使用这个data数据对象,你的处理程序handler应该在返回之前retain持有这个对象或是将其数据拷贝到其他位置。
- error:如果数据被成功读取或一个EOF被达到时返回0。如果发生错误了,这个参数返回一个错误数字。
【讨论】
这是一个从指定文件的当前位置启动一个简单的,异步的读取操作的方便方法。
这个方法是被用于那些不需要你花费创建一个通道的开销和不计划分很多步骤来读取和写入数据的简单操作。一旦提交,就没有取消读取操作的方法。
调用本方法之后,在这个handlerblock入列之前是系统控制着这个指定文件描述符。当它控制了这个文件描述符,系统可以代表程序修改它。例如,系统会典型的添加 0_NONBLOCK 这个flag来确保任何的操作是non-blocking的。在这期间,你的程序直接的修改文件描述符是错误的。然后,你可能需要传入这个文件描述符到这个方法或 dispatch_write 方法中来执行额外的读取或写入。你可能也要使用这个文件描述符来创建新的调度I/O通道。
你提供的这个handler块不放入队列执行,直到读取操作完成。此外,如果你使用这个便利的API对同一个文件同时发起多个读和写的操作,所有的这些操作应该在任何关联的handler入队列之前完成。如果你已经通过其他的通道使用了这个文件描述符,你应该使用 dispatch_io_read 方法来从通道中读取数据而不是使用本方法。
如果你试图去读取文件末尾之后的数据,你的hanlder块将返回一个空的数据对象并且error为0。其他的不可回收的错误类型,总会伴随着一个适当的错误码的返回,无论在错误发生之前数据被读取了。
【有效性】
在 iOS 5.0 及以上版本可用。
dispatch_write
- 使用这个特殊的文件描述符来异步的执行写入的操作
【描述】
void dispatch_write ( dispatch_fd_t fd, dispatch_data_t data, dispatch_queue_t queue, void (^handler)(dispatch_data_t data, int error) );
【参数】
- 与dispatch_read 类似。
【讨论】
- 与dispatch_read 类似。
【有效性】
在 iOS 5.0 及以上版本可用。
- 未完待续。