Thank you for that very insightful response! I appreciate it, and learned a lot.
Responding to your question below. Hopefully this will give a bit more context to what I am doing and why.
What are you actually waiting on? In general, I've become very nervous anytime I see code that uses dispatch groups because they seem to be used as a slightly awkward "band-aid" trying to make something work that doesn't really want to work. Case in point here, the main reason an NSE would be waiting is network activity, in which case the simpler solution would be to simply set the right timeout on that network activity.
For example, let's say 3 async things are happening:
Call a reporting API
Call a service metric API
Download an attachment
I don't want to call contentHandler until I have given them all adequate time to complete. My understanding is once contentHandler is called, the system will kill the NSE process.
Alternatively I could not call the contentHandler, and let the full ~25-30 seconds run and let the system kill it. However for obvious reasons I wouldn't want to do that and I doubt that would be an encouraged solution.
I am thinking about doing something that approximates the following. Let me know if this makes sense or if I am over complicating it.
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self reportReceivedWithTimeout:5 completion:^(BOOL success) {
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self publishMetricsWithTimeout:5 completion:^(BOOL success) {
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self downloadAttachmentWithTimeout:5 completion:^(BOOL success) {
dispatch_group_leave(group);
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[self callContentHandler];
});