GCD
主队列
在主线程中调用同步执行+主队列
//在主线程中调用同步执行+主队列
-(void)syncMain{
NSLog(@"currentHead---%@",[NSThread currentThread]);
NSLog(@"syncMain begin");
// 获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
//追加任务1
[NSThread sleepForTimeInterval:2]; //模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
//追加任务2
[NSThread sleepForTimeInterval:2];
NSLog(@"2---%@",[NSThread currentThread]);
});
NSLog(@"syncMain end");
}
打印结果如下
**2021-03-26 16:47:18.322216+0800 GCD-test[5676:241439] currentHead---<NSThread: 0x600001930080>{number = 1, name = main}**
**2021-03-26 16:47:18.322446+0800 GCD-test[5676:241439] syncMain begin**
**(lldb)**
追加到主队列中的任务1、2都没有执行,且最后的syncMain end
也没有打印,程序直接崩溃,这是为什么?
因为我们在主线程中执行 syncMain
方法,相当于把syncMain
任务放到了主线程的队列中
而同步执行会等待当前队列中的任务执行完毕,才会接着执行
当我们又把任务1追加到主队列中时,也就是将任务1放到主线程中执行
此时,主线程的队列正在执行syncMain
任务,即任务1在等待syncMain
任务的执行完毕,而syncMain
任务又需要等待任务1执行完毕,才能接着执行下面的任务2等
最终导致了**syncMain
任务和任务1都在等待对方执行完毕**,导致了死锁
在其他线程中调用同步执行+主队列
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// [self syncMain];
[NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
}
//在其他中调用同步执行+主队列
-(void)syncMain{
NSLog(@"currentHead---%@",[NSThread currentThread]);
NSLog(@"syncMain begin");
// 获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
//追加任务1
[NSThread sleepForTimeInterval:2]; //模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
//追加任务2
[NSThread sleepForTimeInterval:2];
NSLog(@"2---%@",[NSThread currentThread]);
});
NSLog(@"syncMain end");
}
打印结果如下
2021-03-26 16:57:24.693109+0800 GCD-test[5793:248991] currentHead---<NSThread: 0x600003c86f00>{number = 5, name = (null)}
2021-03-26 16:57:24.693560+0800 GCD-test[5793:248991] syncMain begin
2021-03-26 16:57:26.695160+0800 GCD-test[5793:248916] 1---<NSThread: 0x600003cc8240>{number = 1, name = main}
2021-03-26 16:57:28.696918+0800 GCD-test[5793:248916] 2---<NSThread: 0x600003cc8240>{number = 1, name = main}
2021-03-26 16:57:28.697189+0800 GCD-test[5793:248991] syncMain end
可以看到syncMain
任务在主线程中正常执行,任务顺序执行
因为syncMain
任务放在了其他线程中,而任务1、2被追加到了主队列中,在主线程中执行,而主队列此时没有正在执行的任务,所以主线程会执行任务1,任务1执行完毕后,再继续将任务2添加到主队列中,此时主队列也没有其他任务,主线程也不会被卡住,不会造成死锁
异步执行+主队列
-(void)asyncMain{
NSLog(@"currentHead---%@",[NSThread currentThread]);
NSLog(@"asyncMain begin");
// 获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
//追加任务1
[NSThread sleepForTimeInterval:2]; //模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//追加任务2
[NSThread sleepForTimeInterval:2];
NSLog(@"2---%@",[NSThread currentThread]);
});
NSLog(@"asyncMain end");
}
打印结果如下
2021-03-26 17:04:17.984120+0800 GCD-test[5917:254579] currentHead---<NSThread: 0x600000dc0380>{number = 1, name = main}
2021-03-26 17:04:17.984304+0800 GCD-test[5917:254579] asyncMain begin
2021-03-26 17:04:17.984478+0800 GCD-test[5917:254579] asyncMain end
2021-03-26 17:04:19.985017+0800 GCD-test[5917:254579] 1---<NSThread: 0x600000dc0380>{number = 1, name = main}
2021-03-26 17:04:21.985997+0800 GCD-test[5917:254579] 2---<NSThread: 0x600000dc0380>{number = 1, name = main}
所有任务都是在主线程中执行的,没有开启其他线程,异步执行虽然具备开启新线程的能力,但因为是主队列,所以所有任务都放在主线程中
任务是在打印完 asyncMain begin
和 asyncMain end
后执行的,是因为异步执行不会做任何等待,可以继续执行任务
GCD线程间的通信
在iOS开发中,我们一般在主线程中刷新UI,例如:点击、滚动、拖拽等事件
我们通常把一些耗时操作放在其他线程,例如:文件上传、图片下载等耗时操作
而有时当我们在其他线程执行完耗时操作后,需要回到主线程,那么就用到了线程间的通信
//线程间通信
-(void)communicate{
//获得全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 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]);
});
});
}
打印结果
2021-03-26 17:17:51.144443+0800 GCD-test[6057:264059] 1---<NSThread: 0x600000702b40>{number = 5, name = (null)}
2021-03-26 17:17:53.144938+0800 GCD-test[6057:263886] 2---<NSThread: 0x600000740400>{number = 1, name = main}
可以看到先在其他线程执行完任务1,然后回到主线程执行任务2
GCD的其他方法
栅栏函数:dispatch_barrier_async
异步执行+并发队列时会开启新的线程,且任务并发执行,但是我们无法设置任务执行的顺序
//异步执行+并发队列
-(void)asycnConcurrent{
NSLog(@"currentHead---%@",[NSThread currentThread]);
NSLog(@"asycnConcurrent begin");
// 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("hahaha", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
//追加任务1
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//追加任务2
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//追加任务3
NSLog(@"3---%@",[NSThread currentThread]);
});
NSLog(@"asycnConcurrent end");
}
打印结果:可以看到任务执行顺序是2、3、1
2021-03-26 17:36:24.123041+0800 GCD-test[6331:277548] currentHead---<NSThread: 0x6000029980c0>{number = 1, name = main}
2021-03-26 17:36:24.123234+0800 GCD-test[6331:277548] asycnConcurrent begin
2021-03-26 17:36:24.123398+0800 GCD-test[6331:277548] asycnConcurrent end
2021-03-26 17:36:24.123460+0800 GCD-test[6331:277635] 2---<NSThread: 0x6000029cec40>{number = 6, name = (null)}
2021-03-26 17:36:24.123578+0800 GCD-test[6331:277633] 3---<NSThread: 0x6000029d39c0>{number = 7, name = (null)}
2021-03-26 17:36:24.123583+0800 GCD-test[6331:277636] 1---<NSThread: 0x6000029de700>{number = 3, name = (null)}
为了控制并发队列的任务执行顺序,例如有任务1、2、3,我们要求任务3必须要在任务1、2完成后再执行,应该怎么办?
栅栏函数可以控制多线程异步的任务执行顺序
注意,栅栏函数不能使用全局并发队列
//栅栏函数
-(void)barrier{
dispatch_queue_t queue = dispatch_queue_create("hahaha", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
//追加任务1
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//追加任务2
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
//追加任务barrier
NSLog(@"------barrier------%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
//追加任务3
NSLog(@"3---%@",[NSThread currentThread]);
});
}
打印结果
2021-03-26 17:44:31.413739+0800 GCD-test[6463:285495] 1---<NSThread: 0x6000019e80c0>{number = 6, name = (null)}
2021-03-26 17:44:31.413746+0800 GCD-test[6463:285498] 2---<NSThread: 0x6000019f57c0>{number = 7, name = (null)}
2021-03-26 17:44:33.415331+0800 GCD-test[6463:285359] ------barrier------<NSThread: 0x6000019a8240>{number = 1, name = main}
2021-03-26 17:44:35.420804+0800 GCD-test[6463:285498] 3---<NSThread: 0x6000019f57c0>{number = 7, name = (null)}
可以看到通过在中间设置栅栏后,任务3是在任务1、2都执行完后才执行的,但是在栅栏函数前的任务1、2的执行顺序还是无法控制的
延迟执行:dispatch_after
GCD的延迟执行方法
//延迟执行-GCD
-(void)delay_gcd{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
NSLog(@"GCD delay --- %@",[NSThread currentThread]);
});
}
打印结果
2021-03-26 22:30:59.741605+0800 GCD-test[9721:429049] GCD delay --- <NSThread: 0x6000019f8280>{number = 1, name = main}
使用GCD的延迟执行的好处是可以选择想要执行的任务在哪个线程中完成,上面这个例子是在主线程中执行的,下面来看一个在子线程中执行的例子
//延迟执行-GCD
-(void)delay_gcd{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
NSLog(@"GCD delay --- %@",[NSThread currentThread]);
});
}
打印结果
2021-03-26 22:35:48.193273+0800 GCD-test[9804:433026] GCD delay --- <NSThread: 0x600001718bc0>{number = 4, name = (null)}
除了GCD之外还有两种常用的延迟执行方法
-
//延迟执行——1 -(void)delay_performselector{ [self performSelector:@selector(task) withObject:nil afterDelay:2]; }
-
//延迟执行-2 -(void)delay_nstimer{ [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(task) userInfo:nil repeats:NO]; }
一次性代码:dispatch_once
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self once];
}
-(void)once{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"dispatch_once --- %@",[NSThread currentThread]);
});
}
打印结果
注意:即使再次点击屏幕也不会再打印
2021-03-26 22:40:31.463259+0800 GCD-test[9911:438448] dispatch_once --- <NSThread: 0x600000238400>{number = 1, name = main}
一次性代码在整个应用程序的生命周期只会执行一次,可以看到onceToken
是用static
修饰的,是全局的,且只会在应用程序释放的时候这个变量才会被释放掉
一次性代码的常用场景:单例模式
(所以注意!一次性代码不能放在懒加载里面)
快速迭代
//第一个参数:遍历的次数
//第二个参数:队列 (注意只能传并发队列)
//第三个参数:index 索引
-(void)apply_demo{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%zd---%@",index,[NSThread currentThread]);
});
}
打印结果
2021-03-26 23:13:58.750090+0800 GCD-test[10433:468003] 1---<NSThread: 0x600002e7e940>{number = 6, name = (null)}
2021-03-26 23:13:58.750102+0800 GCD-test[10433:468000] 0---<NSThread: 0x600002e110c0>{number = 5, name = (null)}
2021-03-26 23:13:58.750102+0800 GCD-test[10433:468002] 2---<NSThread: 0x600002e72e80>{number = 4, name = (null)}
2021-03-26 23:13:58.750316+0800 GCD-test[10433:468000] 5---<NSThread: 0x600002e110c0>{number = 5, name = (null)}
2021-03-26 23:13:58.750316+0800 GCD-test[10433:468003] 4---<NSThread: 0x600002e7e940>{number = 6, name = (null)}
2021-03-26 23:13:58.750330+0800 GCD-test[10433:468002] 6---<NSThread: 0x600002e72e80>{number = 4, name = (null)}
2021-03-26 23:13:58.750525+0800 GCD-test[10433:468000] 8---<NSThread: 0x600002e110c0>{number = 5, name = (null)}
2021-03-26 23:13:58.750525+0800 GCD-test[10433:468003] 9---<NSThread: 0x600002e7e940>{number = 6, name = (null)}
2021-03-26 23:13:58.750525+0800 GCD-test[10433:468002] 7---<NSThread: 0x600002e72e80>{number = 4, name = (null)}
2021-03-26 23:13:58.750145+0800 GCD-test[10433:467851] 3---<NSThread: 0x600002e38740>{number = 1, name = main}
2021-03-26 23:13:58.752066+0800 GCD-test[10433:467851] apply---end
可以看到打印不一定是按照0-9的顺序的,因为是并发执行的
但是apply---end
一定是在最后执行,因为 dispatch_apply
方法会等待全部任务执行完毕
快速迭代顾名思义就是快速的迭代,相对于for循环可以更快的执行
for循环是在主线程中执行且是同步执行的,而快速迭代内部会开子线程,然后有子线程和主线程一起来并发的执行任务
快速迭代的简单应用,举个例子:文件的转移
-(void)moveFileWithGCD{
//1. 拿到文件路径
NSString *from = @"/Users/juice/Desktop/from";
//2. 拿到目标文件路径
NSString *to = @"/Users/juice/Desktop/to";
//3. 得到目录下面的所有文件名
NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
//4. 遍历所有文件,执行剪切操作
NSInteger count = subPaths.count;
dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index) {
//4.1 拼接文件的全路径,这个方法会自动加上“/”
NSString *fullPath = [from stringByAppendingPathComponent:subPaths[index]];
NSString *toFullPath = [to stringByAppendingPathComponent:subPaths[index]];
//4.2 执行剪切操作
//第一个参数:要被剪切的文件路径
//第二个参数:文件要被存放到哪个位置
[[NSFileManager defaultManager]moveItemAtPath:fullPath toPath:toFullPath error:nil];
NSLog(@"%@----%@----%@",fullPath,toFullPath,[NSThread currentThread]);
});
}
打印结果
2021-03-26 23:35:50.944679+0800 GCD-test[10770:484969] /Users/juice/Desktop/from/.DS_Store----/Users/juice/Desktop/to/.DS_Store----<NSThread: 0x60000177cb00>{number = 1, name = main}
2021-03-26 23:35:50.944725+0800 GCD-test[10770:485221] /Users/juice/Desktop/from/截屏2021-03-26 23.27.10.png----/Users/juice/Desktop/to/截屏2021-03-26 23.27.10.png----<NSThread: 0x600001723940>{number = 6, name = (null)}
2021-03-26 23:35:50.944824+0800 GCD-test[10770:485127] /Users/juice/Desktop/from/截屏2021-03-26 23.27.17.png----/Users/juice/Desktop/to/截屏2021-03-26 23.27.17.png----<NSThread: 0x60000172a980>{number = 7, name = (null)}
2021-03-26 23:35:50.944839+0800 GCD-test[10770:485220] /Users/juice/Desktop/from/截屏2021-03-26 23.27.15.png----/Users/juice/Desktop/to/截屏2021-03-26 23.27.15.png----<NSThread: 0x6000017205c0>{number = 8, name = (null)}
队列组
例如当一个队列组执行完毕后才执行下一个队列组,即监听一个队列组任务的完成状态
dispatch_group_notify
-(void)groupNotify{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"4---%@",[NSThread currentThread]);
NSLog(@"group---end");
});
}
2021-03-26 23:54:27.197455+0800 GCD-test[11021:498748] 1---<NSThread: 0x600003a07980>{number = 5, name = (null)}
2021-03-26 23:54:27.197490+0800 GCD-test[11021:498750] 2---<NSThread: 0x600003a7cb00>{number = 6, name = (null)}
2021-03-26 23:54:27.197521+0800 GCD-test[11021:498747] 3---<NSThread: 0x600003a64300>{number = 7, name = (null)}
2021-03-26 23:54:27.197659+0800 GCD-test[11021:498747] 4---<NSThread: 0x600003a64300>{number = 7, name = (null)}
2021-03-26 23:54:27.197755+0800 GCD-test[11021:498747] group---end
当group所有的任务执行完毕后,notify通知(拦截通知)
注意notify不是阻塞的,这个方法本身也是异步的,如果notify下面还有方法会继续执行
dispatch_group_enter、dispatch_group_leave
-(void)groupEnterAndLeave{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//在该方法后面的异步任务会被纳入到队列组的监听范围,进入群组
dispatch_group_enter(group);
dispatch_async(queue, ^{
//追加任务1
NSLog(@"1---%@",[NSThread currentThread]);
//离开群组
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
//追加任务2
NSLog(@"2---%@",[NSThread currentThread]);
//离开群组
dispatch_group_leave(group);
});
}
dispatch_group_enter和dispatch_group_leave必须要配对使用
dispatch_async(queue, ^{
//追加任务2
NSLog(@"2---%@",[NSThread currentThread]);
//离开群组
dispatch_group_leave(group);
});
//其实就等价于
dispatch_group_async(group, queue, ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_group_wait
-(void)groupWait{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
NSLog(@"3---%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"4---%@",[NSThread currentThread]);
});
NSLog(@"-----end----");
}
打印结果
2021-03-27 15:39:05.993676+0800 GCD-test[17321:752515] 1---<NSThread: 0x600000b8bd80>{number = 5, name = (null)}
2021-03-27 15:39:05.993672+0800 GCD-test[17321:752516] 2---<NSThread: 0x600000b8a640>{number = 4, name = (null)}
2021-03-27 15:39:05.993986+0800 GCD-test[17321:752469] -----end----
2021-03-27 15:39:05.994110+0800 GCD-test[17321:752515] 4---<NSThread: 0x600000b8bd80>{number = 5, name = (null)}
2021-03-27 15:39:05.994426+0800 GCD-test[17321:752516] 3---<NSThread: 0x600000b8a640>{number = 4, name = (null)}
dispatch_group_wait是死等,阻塞的,直到队列组的所有任务都执行完毕后才能执行
应用场景
- 下载图片1,开子线程
- 下载图片2,开子线程
- 合成图片并显示图片,开子线程
可以看到步骤3依赖于步骤1、2的完成才可执行
-(void)download{
//创建队列组和队列
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//开启子线程
dispatch_async(queue, ^{
NSLog(@"image1----%@",[NSThread currentThread]);
//1.下载图片1
//1.1 确定URL
NSURL *url = [NSURL URLWithString:@"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2894455039,838130676&fm=26&gp=0.jpg"];
//1.2 下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
//1.3 转换图片
self.image1 = [UIImage imageWithData:imageData];
});
//开启子线程
dispatch_async(queue, ^{
NSLog(@"image2----%@",[NSThread currentThread]);
//2.下载图片2
//2.1 确定URL
NSURL *url = [NSURL URLWithString:@"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F201906%2F23%2F20190623142123_SZva4.thumb.400_0.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619515368&t=e8c1d14fc46795e6e739a7061ad384b8"];
//2.2 下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
//2.3 转换图片
self.image2 = [UIImage imageWithData:imageData];
});
//3. 合并图片
dispatch_group_notify(group, queue, ^{
NSLog(@"合并image----%@",[NSThread currentThread]);
//3.1 创建图形上下文
UIGraphicsBeginImageContext(CGSizeMake(400, 400));
//3.2 画图1
[self.image1 drawInRect:CGRectMake(0, 0, 400, 200)];
//3.3 画图2
[self.image2 drawInRect:CGRectMake(0, 200, 400, 200)];
//3.4 根据上下文得到一张图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//3.5 关闭上下文
UIGraphicsEndImageContext();
//3.6 更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"更新UI----%@",[NSThread currentThread]);
self.imageView.image = image;
});
});
}
打印结果
2021-03-28 17:35:34.227509+0800 GCD-test[1313:33317] image1----<NSThread: 0x6000033bca40>{number = 6, name = (null)}
2021-03-28 17:35:34.227519+0800 GCD-test[1313:33311] image2----<NSThread: 0x6000033b2140>{number = 7, name = (null)}
2021-03-28 17:35:34.227577+0800 GCD-test[1313:33312] 合并image----<NSThread: 0x6000033aa900>{number = 4, name = (null)}
2021-03-28 17:35:34.243472+0800 GCD-test[1313:33197] 更新UI----<NSThread: 0x6000033ec0c0>{number = 1, name = main}
自己创建的并发队列和全局并发队列的区别
-
全局并发队列在整个应用程序中本身是默认存在的,并且对应有优先级,我们只是选择其中一个优先级的队列来用,而自己创建的是从头开始去创建一个队列
-
如果是在MRC环境下,手动创建的并发队列需要我们release(使用create和retain的函数都是如此),在ARC中手动创建的就不需要我们释放了,而全局并发队列不管是ARC还是MRC都不需要我们负责释放
-
使用栅栏函数时,只能在手动创建的并发队列一起使用时才有效
补充点
- dispatch_async 和 dispatch_async_f 的区别:封装任务的方法不同
- dispatch_async 是用block
- dispatch_async_f 是用函数
//第一个参数:队列
//第二个参数:参数
//第三个参数:函数
dispatch_async_f(<#dispatch_queue_t _Nonnull queue#>, <#void * _Nullable context#>, <#dispatch_function_t _Nonnull work#>)
点击参数 #dispatch_function_t
进去看到函数定义如下:
typedef void (*dispatch_function_t)(void *_Nullable);
我们直接复制后面的 void (*dispatch_function_t)(void *_Nullable);
来定义我们的函数
(*dispatch_function_t)
用函数名(例如task)替换(void *_Nullable)
用参数名替换(param)
替换后函数 :void task(void *param)
这里对应的param
就是 dispatch_async_f
第三个参数传入的值
示例如下
-(void)other{
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
}
void task(void *param){
NSLog(@"%s---%@",__func__,[NSThread currentThread]);
}
打印结果
2021-03-28 17:06:07.255900+0800 GCD-test[3410:118187] task---<NSThread: 0x600001fabf00>{number = 7, name = (null)}
2021-03-28 17:06:07.256018+0800 GCD-test[3410:118182] task---<NSThread: 0x600001fcd240>{number = 4, name = (null)}
2021-03-28 17:06:07.256044+0800 GCD-test[3410:118183] task---<NSThread: 0x600001faaf40>{number = 6, name = (null)}
- 创建队列的时候第一个参数是C语言的字符串,所以不用在前面加@