dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
- The main queue: 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。
- Global queues: 全局队列是并发队列,并由整个进程共享。进程中存在三个全局队列:高、中(默认)、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
- 用户队列: 用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列,所以我们称其为用户队列) 是用函数
dispatch_queue_create
创建的队列. 这些队列是串行和并行的。正因为如此,它们可以用来完成同步机制, 有点像传统线程中的mutex。
常用的函数:
dispatch_resume() 继续执行线程
dispatch_suspend() 挂起线程 中断线程
dispatch_sync() 同步添加操作。他是等待添加进队列里面的操作完成之后再继续执行。
dispatch_async () 异步添加进任务队列,它不会做任何等待
dispatch_get_main_queue() 主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行
dispatch_queue_create() 创建一个队列
第一个参数是一个标签,这纯是为了debug。Apple建议我们使用倒置域名来命名队列,比如“com.dreamingwish.subsystem.task”。这些名字会在崩溃日志中被显示出来,也可以被调试器调用这在调试中会很有用,所有尽量不要重名了。
dispatch_get_global_queue() 全局并发队列,并由整个进程共享, 可设定优先级来选择高、中、低, 后台优先级队列。说明:全局并发队列的优先级
void dispatch_apply(size_t iterations, dispatch_queue_t queue,void (^block)(size_t)) 这个函数调用单一block多次,并平行运算,然后等待所有运算结束,作用是把指定次数指定的block添加到queue中
第一个参数是迭代次数
第二个是所在的队列
第三个是当前索引
<span style="font-size:18px;"><span style="font-size:18px;">// 1. 创建一个串行队列
//参数:1. 队列标签 2. 队列的属性
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);
NSLog(@"开始!!");
// 2. 同步执行任务
// 一般只要使用”同步“执行,串行队列对添加的同步任务,会立马执行
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
</span></span>
2、串行队列,异步(开启多个线程)执行任务
<span style="font-size:18px;"><span style="font-size:18px;"> // 1. 串行队列
// 下面两种写法是一样的
// dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("itcast", NULL);
// 2. 异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
</span></span>
3、并行队列,同步执行任务
<span style="font-size:18px;"><span style="font-size:18px;">//1. 并行队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
// 2. 同步执行任务
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
</span></span>
4、并行队列,异步执行任务
<span style="font-size:18px;"><span style="font-size:18px;"> //1. 并行队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
// 2. 异步执行任务
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
</span></span>
<span style="font-size:18px;">/**
主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程.
异步执行: 会开新线程,在新线程执行
结果: 不开线程, 只能在主线程上面,顺序执行!
*/
- (void)gcdTest5
{
// 1. 获得主队列-> 程序启动,--> 至少有一个主线程-> 一开始就会创建主队列
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"1----");
// 2. 异步执行任务
for (int i = 0; i < 10; i++) {
NSLog(@"调度前---");
// 异步:把任务放到主队列里,但是不需要马上执行
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
NSLog(@"睡会");
[NSThread sleepForTimeInterval:2.0];
}
NSLog(@"完成----");
}
</span>
/**
主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程.
同步执行:要马上执行
结果:死锁
*/
<span style="font-size:18px;">#pragma GCD- 同步任务的作用
- (void)gcdTest7
{
// 并发队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
/**
例子:有一个小说网站
- 必须登录,才能下载小说
有三个任务:
1. 用户登录
2. 下载小说A
3. 下载小说B
*/
// 添加任务
// 同步任务,需要马上执行。 不开新线程
dispatch_sync(queue, ^{
NSLog(@"用户登录 %@", [NSThread currentThread]);
});
//
dispatch_async(queue, ^{
NSLog(@"下载小说A %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下载小说B %@", [NSThread currentThread]);
});
}
</span>
全局队列:也是并发队列
/**
全局队列跟并发队列的区别
1. 全局队列没有名称 并发队列有名称
2. 全局队列,是供所有的应用程序共享。
3. 在MRC开发,并发队列,创建完了,需要释放。 全局队列不需要我们管理
*/
#pragma CGD - 全局队列
- (void)gcdTest8
{
// 获得全局队列
/**
参数:第一个参数,一般 写 0(可以适配 iOS 7 & 8)
iOS 7
DISPATCH_QUEUE_PRIORITY_HIGH 2 高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW (-2) 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级
iOS 8
QOS_CLASS_DEFAULT 0
第二个参数:保留参数 0
*/
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 添加异步任务
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
}
队列的选择:
串行队列异步执行
- 开一条线程,顺序执行
- 效率:不高,执行比较慢,资源占用小 -》省电
一般网络是3G,对想能要求不会很高。
并发队列异步执行
- 开启多条线程,并发执行
- 效率:高,执行快,资源消耗大-》费电
使用场合:
- 网络WiFi,或者需要很快的响应,要求用户体验非常流畅。
-对任务执行顺序没有要求
-同步任务:一般只会在并发队列,需要阻塞后续任务。必须等待同步任务执行完毕,再去执行其他任务。"依赖"关系
线程间的通讯:(重点)
<span style="font-size:18px;">- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%@", [NSThread currentThread]);
// 耗时操作: 放在全局队列,异步执行
// 1. url, 确定一个网络上的资源路径
NSURL *url = [NSURL URLWithString:@"http://fe.topit.me/e/d1/12/1170068721aa112d1el.jpg"];
// 2. 通过url可以下载对应的网络资源, 网络资源传输的都是二进制
NSData *data = [NSData dataWithContentsOfURL:url];
// 3. 二进制转成图片
UIImage *image = [UIImage imageWithData:data];
// 4. 更新UI,在主线程-》 直接把任务添加到主队列,就会在主队列执行
dispatch_async(dispatch_get_main_queue(), ^{
self.iconView.image = image;
NSLog(@"-----%@", [NSThread currentThread]);
});
});
}
</span>
其他用法:
<span style="font-size:18px;">#pragma mark - 调度组(分组)
- (void)group
{
/**
应用场景:
开发的时候,有的时候出现多个网络请求都完成以后(每一个网络请求的事件长短不一定),再统一通知用户
比如: 下载小说:三国演义, 红楼梦, 金X梅
*/
// 实例化一个调度组
dispatch_group_t group = dispatch_group_create();
// 队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 任务添加到队列queue
dispatch_group_async(group, queue, ^{
NSLog(@"下载小说A---%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"下载小说B---%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"下载小说X---%@", [NSThread currentThread]);
});
// 获得所有调度组里面的异步任务完成的通知
// dispatch_group_notify(group, queue, ^{
// NSLog(@"下载完成,请观看%@", [NSThread currentThread]); // 异步的
// });
//注意点: 在调度组完成通知里,可以跨队列通信
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 更新UI,在主线程
NSLog(@"下载完成,请观看%@", [NSThread currentThread]); // 异步的
});
}
</span>
延时执行:
<span style="font-size:18px;"> dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"点我了-- %@", [NSThread currentThread]);
});
</span>
一次性任务:
<span style="font-size:18px;"> dispatch_once(&onceToken, ^{
NSLog(@"%----ld", onceToken);
NSLog(@"真的执行一次么?");
});</span>