在做项目的时候往往会出现多图上传的功能,而恰巧服务器可能只支持单张上传,所以你要遍历请求,而全部上传完成后可能还要刷新列表啊或者给个提示框啊等需求。
有些人可能会一个网络请求成功回调里面再嵌套一个,类推,如果上传9张图就要嵌套9次,很显然这样的代码看上去有点low而且非并发耗时比较慢,推荐使用gcd group 组。话不多说上代码:
//创建一个组
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i <9; I++)
{//模仿多个网络请求
dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{
//异步网络请求
int x = arc4random() % 5;
//模拟网络请求快慢不确定的情况
sleep(x);
NSLog(@"group 请求成功OR请求失败 %d!",i);
});
}
NSLog(@"group开始 网络请求!");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//网络请求完毕 回到主线程更新UI 或者做些其它的操作
NSLog(@"group所有请求完毕!!!");
});
使用dispatch_group_async函数将多个任务关联到一个Dispatch Group和相应的queue中,group会并发地同时执行这些任务。而且Dispatch Group可以用来阻塞一个线程, 直到group关联的所有的任务完成执行调用dispatch_group_notify方法,这样就达到了想要的效果。
当然你也可以不使用dispatch_group_async函数,转而使用dispatch_group_enter和dispatch_group_leave,注意这里要配套使用哦。
dispatch_group_enter:通知group,下面的任务马上要放到group中执行了。
dispatch_group_leave:通知group,任务完成了,该任务要从group中移除了。
//创建一个组
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i <9; I++)
{//模仿多个网络请求
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//异步网络请求
int x = arc4random() % 5;
//模拟网络请求快慢不确定的情况
sleep(x);
NSLog(@"group 请求成功OR请求失败 %d!",i);
dispatch_group_leave(group);
});
}
NSLog(@"group开始 网络请求!");
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//网络请求完毕 回到主线程更新UI 或者做些其它的操作
NSLog(@"group所有请求完毕!!!");
});
还有一种情况,比如要做一个相册功能,也是多图上传,但是要有规律按顺序上传。这里就推荐使用dispatch_semaphore_t 信号量,也是利用线程阻塞来实现。直接上代码:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
/// 创建一个线程"001" 确保之后不要阻塞主线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
/// 创建一个信号量 数值为1 信号量可以让线程阻塞等待
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (int i = 0; i<9; i++) {
/// 模仿9个请求任务
/// 执行dispatch_semaphore_wait 信号量数值 -1.
/// 当i为0此时的信号量数值为0, 当此时的信号量大于等于0继续执行wait函数下面的语句.
/// 当i为1此时的信号量数值为-1, 阻塞当前线程 阻塞时长为DISPATCH_TIME_FOREVER, 不执行wait函数下面的语句.
/// 只有等到执行i为0 的 dispatch_semaphore_signal 方法执行, 信号量数值+1 为0, 唤醒 继续执行wait函数下面的语句.
/// 以此类推循环.
NSLog(@"当前线程:%@",[NSThread currentThread]);
/// ******这是一个网络请求开始******
dispatch_async(dispatch_get_global_queue(0, 0), ^{
/// 模拟异步网络请求
int x = arc4random() % 2;
/// 模拟网络请求快慢
sleep(x);
NSLog(@"执行任务代号:%d",i);
/// 任务结束 信号量数值+1 解放线程"001" 阻塞
dispatch_semaphore_signal(semaphore);
});
/// ******这是一个网络请求结束******
/// 信号量减1 变为负数 当前线程"001" 阻塞
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
});
}
如果需要两者结合使用呢也是可以的,这样即能按顺序上传,又能在上传后收到通知做一些提示或者其它操作,请看代码:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
/// 创建一个线程"001" 确保之后不要阻塞主线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_group_t group = dispatch_group_create();
/// 创建一个信号量 数值为0
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
for (int i = 0; i<9; i++)
{
/// 模仿9个请求任务
dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{
// /// 异步网络请求
// int x = arc4random() % 2;
// /// 模拟网络请求快慢不确定的情况
// sleep(x);
NSLog(@"执行任务:%d 线程:%@",i,[NSThread currentThread]);
/// 任务结束 信号量数值+1 解放线程"001" 阻塞
dispatch_semaphore_signal(semaphore);
});
/// 信号量减1 变为负数 当前线程"001" 阻塞
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//NSLog(@"阻塞线程:%@",[NSThread currentThread]);
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
/// 网络请求完毕 回到主线程更新UI 或者做些其它的操作
NSLog(@"所有任务执行完毕!!!");
});
});
}
想要顺序(同步)执行异步任务的话,可以把一个个异步任务放在串行队列里面去执行,代码如下:
dispatch_queue_t queue = dispatch_queue_create("serial",DISPATCH_QUEUE_SERIAL);
///在串行队列中 执行第一个异步任务
dispatch_async(queue, ^{
NSLog(@"1---%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:5];
NSLog(@"xxxxxxxxxxxxxx");
});
///在串行队列中 执行第二个异步任务
dispatch_async(queue, ^{
NSLog(@"2---%@", [NSThread currentThread]);
});
///在串行队列中 执行第三个异步任务
dispatch_async(queue, ^{
NSLog(@"3---%@", [NSThread currentThread]);
});
如果有不同见解欢迎讨论,有错误还请指出,博主加以改正,谢谢!
转载请说明出处,代码在这里。请不要吝啬您的star