iOS开发中经常会用到多线程的方法来异步处理一些耗时操作,来增加APP的性能及体验,充分利用设备的多核资源。多线程有多重方法实现,下面我们来说一种非常好用的方法GCD。
1.GCD简介
GCD是Grand Central Dispatch的缩写,含义是 “强大的中央调度器”。GCD会自动管理线程的生命周期,我们不需要编写任何的线程管理代码,GCD会自动利用多核。
2.GCD任务和队列
- 同步执行(sync):在当前线程执行,不开启新线程
- 异步执行(async):在新线程执行,开启新线程
- 串行队列(Serial):在一个线程里面一个接着一个的执行任务
- 并行队列(Concurrent):多任务同时执行,开启多个线程
3.队列创建
- 串行队列:dispatch_queue_t queue = dispatch_queue_create(“name1”,DISPATCH_QUEUE_SERIAL);
- 并行队列:dispatch_queue_t queue = dispatch_queue_create(“name2”,DISPATCH_QUEUE_CONCURRENT);
- 主队列:dispatch_queue_t queue = dispatch_get_main_queue();
- 全局并发队列:dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
4.任务
// 同步执行任务创建方法
dispatch_sync(queue, ^{
// 这里放同步执行任务代码
});
// 异步执行任务创建方法
dispatch_async(queue, ^{
// 这里放异步执行任务代码
});
5.线程通信
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(queue, ^{
// 异步追加任务 1
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
// 回到主线程
dispatch_async(mainQueue, ^{
// 追加在主线程中执行的任务
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
});
});
6.GCD栅栏方法(dispatch_barrier_async)
有的时候我们异步操作两个任务,需要第一个任务结束后才去执行第二个任务,这个时候就用到了栅栏方法
dispatch_barrier_async(queue, ^{
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@“barrier—%@”,[NSThread currentThread]);// 打印当前线程
});
当遇到这个方法的时候,方法之前的任务会在他之前先执行完,而他之后的方法会等他执行完之后才会去执行。
7.GCD延时方法(dispatch_after)
有时候我们会遇到需要延时之后才执行某个任务比如按钮不能连续点击,就让按钮延时2秒后才能第二次点击
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2.0 秒后异步追加任务代码到主队列,并开始执行
NSLog(@"after---%@",[NSThread currentThread]); // 打印当前线程
});
8.GCD一次性代码(dispatch_once)
有的时候我们需要在整个项目中某个任务只需要执行一次(单例初始化),我们就可以用GCD方法。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行 1 次的代码(这里面默认是线程安全的)
});
9.GCD快速迭代(dispatch_apply)
我们循环遍历的时候通常用for循环,但是这样的循环是同步执行的效率比较低,GCD提供一种异步的遍历方法可以在多个线程异步遍历
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"apply---begin");
dispatch_apply(6, queue, ^(size_t index) {
NSLog(@"%zd---%@",index, [NSThread currentThread]);
});