Q:

How should I wait for the completion of parallel async tasks in GCD?

Is a dispatch_group and dispatch_group_notify() a reasonable way to wait for parallel async tasks to complete in Objective C with GCD?
Consider the following:
dispatch_group_t requestGroup = dispatch_group_create();
dispatch_group_enter(requestGroup);
dispatch_group_enter(requestGroup);
[asyncCall1 completion:^{
    dispatch_group_leave(requestGroup);
}];

[asyncCall2 completion:^{
    dispatch_group_leave(requestGroup);
}];

dispatch_group_notify(requestGroup, dispatch_get_main_queue(), ^{
    // do something now that both async calls have completed
});

Is this the simplest, best way? The reason I ask is that I have code just like this and generally it  seems to work, though very rarely I have crashes like:
libdispatch.dylib`dispatch_group_leave:
0x394ea4e8:  dmb    ishst
0x394ea4ec:  ldrex  r1, [r0, #0x28]
0x394ea4f0:  adds   r1, #0x1
0x394ea4f2:  strex  r2, r1, [r0, #0x28]
0x394ea4f6:  cmp    r2, #0x0
0x394ea4f8:  bne    0x394ea4ec                ; dispatch_group_leave + 4
0x394ea4fa:  cmp.w  r1, #0xffffffff
0x394ea4fe:  ble    0x394ea50e                ; dispatch_group_leave + 38
0x394ea500:  mvn    r2, #0x80000000
0x394ea504:  cmp    r1, r2
0x394ea506:  it     eq
0x394ea508:  beq.w  0x394edd54                ; _dispatch_group_wake
0x394ea50c:  bx     lr
0x394ea50e:  trap   
0x394ea510:  mov    r8, r8
0x394ea512:  mov    r8, r8

Is this an unconnected crash that's getting caught by the dispatch group?

A:

@Rob was correct and there was a specific case where a completion block could be called twice, meaning that the the calls to dispatch_group_leave() and dispatch_group_enter() were unbalanced, which is unsupported.

