Creating dispatch group
dispatch_group_t group = dispatch_group_create();
I am making 3 same api calls with dispatch wait
[self updateFrequency1];
dispatch_group_wait(group, 3.0);
[self updateFrequency2];
dispatch_group_wait(group, 3.0);
[self updateFrequency3];
dispatch_group_wait(group, 3.0);
Entering in dispatch group
-(void)updateFrequency1{
NSLog(@"updating frequency 1");
dispatch_group_enter(group);
[apimanager makeRequest];
}
-(void)updateFrequency2{
NSLog(@"updating frequency 2");
dispatch_group_enter(group);
[apimanager makeRequest];
}
-(void)updateFrequency3{
NSLog(@"updating frequency 3");
dispatch_group_enter(group);
[apimanager makeRequest];
}
Leaving dispatch group
-(void)responseReceived:(APIResponse*)response{
NSLog(@"leaving dispatch group");
dispatch_group_leave(group);
}
Console log with the above approach is
updating frequency 1
updating frequency 2
updating frequency 3
leaving dispatch group
leaving dispatch group
leaving dispatch group
Instead, I should get
updating frequency 1
leaving dispatch group
updating frequency 2
leaving dispatch group
updating frequency 3
leaving dispatch group
CodePudding user response:
It's just a wild guess whether you have some other parts written correctly or not, but at least the time specified for timeout is wrong. If your timeout is 3 seconds, then dispatch_group_wait
looks as follows:
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 3));
CodePudding user response:
As The Dreams Wind said ( 1), the second parameter of dispatch_group_wait
is incorrect. It should be
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
A second potential problem that can cause the behavior you describe is if you happen to “wait” on the same thread your API manager needs to use. E.g., if you were running on the main thread, and the API manager also dispatches code to the main thread, then you will get the same behavior because your caller is waiting on the thread that the API manager may want to use.
Unrelated to your problem, be aware that, “When a timeout occurs, the group is restored to its original state.” In other words, if it times out, it resumes execution, but the group count is unchanged. Because of this, it is very easy to now let the “enter” and “leave” calls mismatched.
For example, let us imagine that you started the first request, you waited 3 seconds and it timed out because this request was really going to take 5 seconds. So, the “wait” times out, caller resumes execution and initiates the second request while the first is still in progress. But when the first call finally finishes, the dispatch_group_wait
for the second request will be incorrectly satisfied by the dispatch_group_leave
of the first request. Bottom line, this code with timeouts would appear to be fine at first glance, but it is not. You need to check the dispatch_group_wait
return code to determine how to properly proceed.
In short, Be extraordinarily careful about correctness when using timeouts.
Furthermore, you never should “wait”, anyway. Waiting (whether groups, semaphores, locks, etc.) is inefficient. Also, if you do it from the main queue (which you never should), the UI may freeze, you introduce deadlock risks, and if you are unlucky, the OS watchdog process will kill your app.
We would use dispatch_group_notify
. Or, better, we would adopt completion handler patterns and get rid of the dispatch group entirely.