前言
使用dispatch_group过程中,如果发现以下问题:
- crash:leave次数 > enter次数
- notify的block没有回调:leave次数 < enter次数
总之,一定要保证leave和enter的次数相等。
使用场景
多个sevice并发执行,等获取到所有的数据后进行UI刷新。
使用方法
为了方便说明,约定如下:
- 处理多个service的类为:ServiceHandler
- 在ServiceHandler的fetchDataWithFinishBlock:方法中去做统一的网络请求和dispatch_group_notify的调用。
注意点:
- 确保在ServiceHandler里只有一个group
- 在serviceDidStartLoadBlock里做enter
- 在serviceDidFinishLoadBlock和serviceDidFailLoadBlock里做leave
于是,代码大致是这样子的:
- (void)fetchDataWithBlock:(ServiceCallBack)finishBlock {
[service1 getData];
[service2 getData];
[service3 getData];
dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
finishBlock(xxx);
});
}
- (Service *)service1{
if (_service1 == nil) {
_service1 = [[HYUserLevelService alloc] init];
WEAKSELF
_service1.serviceDidStartLoadBlock = ^(WeAppBasicService *service) {
StrongSelf
dispatch_group_enter(strongSelf.group);
};
_service1.serviceDidFinishLoadBlock = ^(WeAppBasicService *service) {
STRONGSELF
dispatch_group_leave(strongSelf.group);
};
_service1.serviceDidFailLoadBlock = ^(WeAppBasicService *service, NSError *error) {
STRONGSELF
NSString* errorMsg = [(KSAdapterService*)service message];
EHLogError(@"err code = %@, err message = %@", [(KSAdapterService*)service code], errorMsg);
dispatch_group_leave(strongSelf.group);
};
}
return _service1;
}
代码说明
在实际使用中,fetchDataWithBlock:可能会被多次调用,而且前后两次调用的时间间隔很短。
-
确保group只有一个:举个例子,如果多次调用中group发生变化,而网络请求又比较慢,会存在第一次网络请求成功后调用dispatch_group_leave时的group已经变成了第二次的group。
-
dispatch_group_enter(group)放到serviceDidStartLoadBlock中,可以比较好的解决可能出现的leave和enter的次数不相等的问题。
-
fetchDataWithBlock:调用多次后notify的block也会回调多次。即使前后调用fetchDataWithBlock:的时间间隔很短(这样service的serviceDidStartLoadBlock和serviceDidFinishLoadBlock只会调用一次)。原因是:多个block被注册到了dispatch_group_notify中,等enter和leave相等时会统一将这些block回调。这里可以根据自己的业务逻辑去处理这些回调是否全部需要。
网友评论