最近看了本书。。。总结一下。。懒呐。。。又好久没写博客了。。。有关iOS多线程的基础知识可以看一下之前的文章iOS多线程。这篇文章主要是总结一下通过Dispatch Group线程组管理页面多个并发请求。
APP的页面有多个请求是很常见的,然后需要几个请求全部回来的之后再刷新页面。如果用串行队列去执行的话效率就显得比较低了。直接使用并发的需要记录每个请求的结果,这样又比较麻烦啰嗦。使用Dispatch Group管理的话,我们只需要并发请求,然后回来只有有统一调回主线程刷新页面即可。
我们先看看Dispatch Group常规的用法
-(void)testGroup3{
//创建一个全局queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建一个dispatch_group_t线程组
dispatch_group_t group = dispatch_group_create();
//执行任务1
dispatch_group_async(group, queue, ^{
NSLog(@"当前线程1:%@",[NSThread currentThread]);
for (int i = 0; i<5; i++) {
NSLog(@"%d",i);
}
});
//执行任务2
dispatch_group_async(group, queue, ^{
NSLog(@"当前线程2:%@",[NSThread currentThread]);
for (int i = 5; i<10; i++) {
NSLog(@"%d",i);
}
});
//执行任务3
dispatch_group_async(group, queue, ^{
NSLog(@"当前线程3:%@",[NSThread currentThread]);
for (int i = 10; i<15; i++) {
NSLog(@"%d",i);
}
});
//任务执行完毕之后收到通知调起主线程刷新页面
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
}
通过代码和log日志,我们可以看出这里使用了dispatch_group_async创建了三条线程并发执行任务,三个并发任务执行完毕后回调给了dispatch_group_notify函数。假如我们把页面的多个请求分别放进去dispatch_group_async任务中,然后请求完成后通过dispatch_group_notify回来main线程中刷新页面是不是可以实现了多个并发请求的需求呢?哈哈。。。那有这么简单啦。。。因为这里我们每次创建一个任务的时候都是看了一个异步线程,如果我们把我们的请求放这个线程中。一般来说我们封装的请求也都是异步请求,那么这样的话一次任务中就有两个异步线程了,还受dispatch_group管理吗?我们改一下上面代码模拟一下。
-(void)testGroup4{
//创建一个全局queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建一个dispatch_group_t线程组
dispatch_group_t group = dispatch_group_create();
//执行任务1
dispatch_group_async(group, queue, ^{
NSLog(@"当前线程1:%@",[NSThread currentThread]);
for (int i = 0; i<5; i++) {
NSLog(@"%d",i);
}
//开一个异步线程,模拟请求
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"接口请求线程1:%@",[NSThread currentThread]);
//当前线程睡眠3S,模拟请求过程
sleep(3);
NSLog(@"请求完成1");
});
});
//执行任务2
dispatch_group_async(group, queue, ^{
NSLog(@"当前线程2:%@",[NSThread currentThread]);
for (int i = 5; i<10; i++) {
NSLog(@"%d",i);
}
//开一个异步线程,模拟请求
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"接口请求线程2:%@",[NSThread currentThread]);
//当前线程睡眠3S,模拟请求过程
sleep(3);
NSLog(@"请求完成2");
});
});
//执行任务3
dispatch_group_async(group, queue, ^{
NSLog(@"当前线程3:%@",[NSThread currentThread]);
for (int i = 10; i<15; i++) {
NSLog(@"%d",i);
}
//开一个异步线程,模拟请求
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"接口请求线程3:%@",[NSThread currentThread]);
//当前线程睡眠3S,模拟请求过程
sleep(3);
NSLog(@"请求完成3");
});
});
//任务执行完毕之后收到通知调起主线程刷新页面
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
}
这里面我们主要是在线程组中另外开了一个异步线程模拟数据请求的过程,通过log日志中我们可以看出dispatch_group_notify中已经打印出来了done,并没有在请求完成之后才执行的。所以这种方法并不能直接实现多个并发请求统一管理的。
使用 dispatch_group_enter()和dispatch_group_leave()结合方式实现
在线程组中, dispatch_group_enter()和dispatch_group_leave()结合使用,enter进入线程,然后leave离开线程,当线程组中enter和leave两个对应了之后,dispatch_group_notify就可以收到通知,执行里面的代码。明显我们可以利用这一特征实现我们的多个并发请求统一管理,下面看看实现代码。
-(void)testGroup2
{
dispatch_group_t groupQueue = dispatch_group_create();
//开始请求1
dispatch_group_enter(groupQueue);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"当前线程1:%@",[NSThread currentThread]);
NSLog(@"开始请求1....");
sleep(2);
NSLog(@"请求1完毕....");
//请求完毕后离开线程
dispatch_group_leave(groupQueue);
});
//开始请求2
dispatch_group_enter(groupQueue);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"当前线程2:%@",[NSThread currentThread]);
NSLog(@"开始请求2....");
sleep(2);
NSLog(@"请求2完毕....");
//请求完毕后离开线程
dispatch_group_leave(groupQueue);
});
dispatch_group_notify(groupQueue, dispatch_get_main_queue(), ^{
NSLog(@"所有请求完毕。。刷新UI");
});
}
首先我们先enter线程组,然后开启请求数据,请求完成之后再leave线程组,这是一次请求的完整过程,可以这个方式来管理过个线程。从log日志中可以看出,在全部leave之后,dispatch_group_notify才接到通知执行里面的代码。
swift中的实现
let group = DispatchGroup()
group.enter()
self.viewModel.getSaleDetail(controller: self, succeedBlock: {
group.leave()
})
group.enter()
self.viewModel.getExceptionData(req: req) {
group.leave()
}
group.enter()
self.viewModel.getZeroStock(req: req) {
group.leave()
}
group.enter()
self.viewModel.getSupplyStock(req: req) {
group.leave()
}
group.notify(queue: DispatchQueue.main) {
self.setUI()
}