本文的主要内容是:
- 什么是GCD
- 了解GCD前,需要了解的基础知识
- GCD的使用
- 使用注意事项
-GCD学习前铺垫-
什么是GCD
- GCD (Grand Central Dispatch) 是Apple公司开发的一种技术,它旨在优化多核环境中的并发操作并取代传统多线程的编程模式
- GCD是基于C语言的线程管理方案,使用者无需过多参与线程的管理,只需要将想要执行的代码,添加到想要添加的调度队列即可
- 在Mac OS X 10.6雪豹中首次推出,并在iOS4.0中引入到了iOS
- GCD主要用在后台执行较慢任务;延迟执行任务;以及在后台任务中,切换回主线程,更新UI
iOS中常用的其它多线程技术
pthread:通用于Unix/Linux/Windows的C语言线程管理API,可移植性强,但是使用繁琐,需要使用者管理线程生命周期
NSThread:使用Objective-C实现,轻量级的线程管理,但是也需要手动管理线程的生命周期
NSOperation:基于GCD,使用Objective-C实现的面向对象的线程管理,比GCD更高级,但是处理简单任务会比GCD代码更多
总之,iOS里GCD用的很多
GCD知识铺垫
竞争&同步:两个线程抢夺同一个资源,就会竞争,为了防止竞争,一个线程拥有资源的时候,会对资源加锁,另一个线程就要等待解锁以后再拥有这个资源,这叫同步。
死锁:两个线程互相等待对方释放资源
主线程&后台线程:主线程也叫前台线程,程序启动的默认线程,操作UI的线程。后台线程,即非主线程,用于不影响主线程的完成一些任务
并行&串行:并行,就是几个任务一起完成。串行,就是几个任务一个接着一个完成。
同步&异步:同步执行线程,等待新线程执行完以后,再继续执行当前线程,很少用到。异步执行线程,在执行新线程的同时,继续执行当前线程,常用。
-GCD的使用-
GCD的使用步骤
- 创建线程队列:主队列,全局并行队列,手动创建串行队列
- 选择执行方式:同步(较少使用),异步,延时
- 添加需要执行的任务:也就是想要创建队列做什么,以Block块语句形式创建
- 任务被执行:Block按照设计被执行
举例
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"我在五秒后打印");
});
NSLog(@"线程被部署");
这段代码的原型如下
void dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
- 首先,创建线程队列,本例中我们使用主队列,所以直接使用dispatch_get_main_queue()
- 然后,选择执行方式,本例使用延时方法dispatch_after
- 添加需要执行的任务,我们打印了一下log
4.任务被执行:
异步执行线程
异步后台线程
主要用途:执行较慢的任务,例如大量计算,网络请求等
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"在异步并行队列中执行");
});
dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);
dispatch_async(queue, ^{
NSLog(@"在异步串行队列中执行");
});
上面的代码,分别创建了一个异步后台并行线程和一个自创建的异步后台串行线程。
异步主线程
主要用途:用于在后台线程的任务将要完成时,切换到主线程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"在异步主线程中执行");
});
同步执行线程
同步后台线程
主要用途:在新线程中执行任务,并且等待线程执行完毕再向后执行,几乎不用
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"在同步并行队列中执行");
});
dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);
dispatch_sync(queue, ^{
NSLog(@"在同步串行队列中执行");
});
上面的代码,分别创建了一个异步后台并行线程和一个自创建的异步后台串行线程。
同步主线程(慎用)
主要用途:只有在其它线程中才可能执行此方法,否则会死锁
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@“在同步主线程中执行,慎用,否则会死锁”);
});
延时执行线程
主要用途:用于等待一段时间以后再执行的任务
dispatch_queue_t queue = dispatch_get_main_queue();
// 也可以使用其它线程
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue2", NULL);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
NSLog(@"延时2秒执行");
});
NSLog(@"延时线程已部署");
-GCD的总结-
创建线程队列
主队列:
dispatch_queue_t queue = dispatch_get_main_queue();
全局并行队列:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
手动创建串行队列:
dispatch_queue_t queue = dispatch_queue_create("com.realank.GCDDemo.myQueue", NULL);
线程执行方式
异步:
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步(慎用):
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
延时:
void dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
关于循环强引用
在block中使用self,或者使用属性(会隐含调用self),会让block持有其类实例,如果此时block,又被存储为类实例的copy或strong属性,就会造成循环强引用。
在GCD的block使用中,不会造成类实例对block的引用,但是为了以防万一,我习惯在Block中统一使用weakSelf来引用属性或方法。
__weak __typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
weakSelf.string = @“hello";
});