dispatch_queue_t
队列对应一个dispatch_queue_t对象即:
dispatch_queue_t queue;
类似普通OC对象,可以用dispatch_retain()和dispatch_release()对其进行内存管理,当一个任务加入到一个queue中的时候,任务会retain这个queue,直到任务执行完成才会release。iOS6之后dispatch对象已经支持ARC,所以在ARC工程之下,我们可以不用担心他的内存。
一般情况下只需要用strong申明一个dispatch的属性。
@property (nonatomic, strong) dispatch_queue_t queue;
如果你是写一个framework,framework的使用者的SDK有可能还是古董级的iOS6之前。那么你需要根据OS_OBJECT_USE_OBJC做一个判断是使用strong还是assign。(一般github上的优秀第三方库都会这么做)
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong) dispatch_queue_t queue;
#else
@property (nonatomic, assign) dispatch_queue_t queue;
#endif
获取主线程队列
主线程是我们最常用的线程,获取主线程队列的方法很简单:
dispatch_queue_t mainQueue;
mainQueue = dispatch_get_main_queue();
假设要在主线程更新UI:
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUI];
});
执行加入到主线程队列的block,App会调用dispatch_main(), NSApplicationMain(),或者在主线程使用CFRunLoop。
获取全局队列
除了主线程队列,GCD提供了几个全局队列,可以直接获取使用
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
dispatch_get_global_queue方法获取的全局队列都是并行队列,并且队列不能被修改,也就是说对全局队列调用dispatch_suspend(), dispatch_resume(), dispatch_set_context()等方法无效。
全局队列对于程序来说是全局的,retain和release会被全局队列忽略。所以,我们不需要存储这些队列的引用数。
identifier: 用以标识队列优先级,推荐用qos_class枚举作为参数,也可以使用dispatch_queue_priority_t
flags: 预留字段,传入任何非0的值都可能导致返回NULL
代码示例:
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
全局队列的四种类型
DISPATCH_QUEUE_PRIORITY_HIGH : 最高优先级,交互级别。使用这个优先级会占用几乎所有的系统CUP和I/O带宽,仅限用于交互的UI操作,比如处理点击事件,绘制图像到屏幕上,动画等
DISPATCH_QUEUE_PRIORITY_DEFAULT : 默认优先级,当没有设置优先级的时候,线程默认优先级。一般情况下用的都是这个优先级
DISPATCH_QUEUE_PRIORITY_LOW : 普通优先级,主要用于不需要立即返回的任务
DISPATCH_QUEUE_PRIORITY_BACKGROUND : 后台优先级,用于用户几乎不感知的任务。它会等待所有比它级别高的队列中的任务执行完或CPU空闲的时候才会执行自己的任务。例如磁盘的读写操作非常耗时,如果我们不需要立即获取到磁盘的数据,我们可以把读写任务放到后台队列中,这样读写任务只会在恰当的时候去执行而不会影响需要更改优先级的其他任务,整个程序也会更加有效率。
由于NULL等于0,也就是DISPATCH_QUEUE_PRIORITY_DEFAULT,所以将0或者NULL传入作为参数返回的是默认优先级:
dispatch_get_global_queue(NULL, NULL)
创建串行队列&并发队列
当无法获取到理想的队列时,我们可以自己创建队列:
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
label: 队列的名称,调试的时候可以区分其他的队列
attr: 队列的属性,dispatch_queue_attr_t类型。用以标识队列串行,并行,以及优先级等信息
attr参数有三种传值方式:
// 串行
#define DISPATCH_QUEUE_SERIAL NULL
// 并行
#define DISPATCH_QUEUE_CONCURRENT \
DISPATCH_GLOBAL_OBJECT(dispatch_queue_attr_t, \
_dispatch_queue_attr_concurrent)
// 自定义属性值
dispatch_queue_attr_t dispatch_queue_attr_make_with_qos_class(dispatch_queue_attr_t attr, dispatch_qos_class_t qos_class, int relative_priority);
DISPATCH_QUEUE_SERIAL 或者 NULL,表示创建串行队列,优先级为目标队列优先级。
DISPATCH_QUEUE_CONCURRENT,表示创建并行队列,优先级也为目标队列优先级。
另外, 自定义属性值
dispatch_queue_attr_make_with_qos_class函数可以创建带有优先级的dispatch_queue_attr_t对象。通过这个对象可以自定义queue的优先级。
attr: 传入DISPATCH_QUEUE_SERIAL、NULL或DISPATCH_QUEUE_CONCURRENT,表示串行或者并行
qos_class: 传入qos_class枚举,表示优先级级别
relative_priority: 相对于qos_class的相对优先级,qos_class用于区分大的优先级级别,relative_priority表示大级别下的小级别。relative_priority必须大于QOS_MIN_RELATIVE_PRIORITY小于0,否则将返回NULL。从GCD源码中可以查到QOS_MIN_RELATIVE_PRIORITY等于-15
使用dispatch_queue_attr_make_with_qos_class创建队列时,需要注意,非法的参数可能导致dispatch_queue_attr_make_with_qos_class返回NULL,dispatch_queue_create传入NULL会创建出串行队列。写代码过程中需要确保这是否是预期的结果
常用创建队列代码示例:
//串行队列
dispatch_queue_t serialQueue;
serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL);
//并发队列
dispatch_queue_t concurrentQueue;
concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);