18

This happens very rarely. Here is the last line of the stack trace:

0  libdispatch.dylib              0x0000000197a85a9c dispatch_group_leave + 48

dispatch_group_leave is called in a complete closure which is invoked like this:

  dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                { () -> Void in
                    let query = HKStatisticsCollectionQuery(quantityType: quantityType,
                        quantitySamplePredicate: nil,
                        options: statisticOptions,
                        anchorDate: anchorDate,
                        intervalComponents: interval)
                    query.initialResultsHandler = {

                        complete()

So we dispatch to a background thread, run a HKStatisticsCollectionQuery, and then call a function parameter closure called complete. Inside complete is where the dispatch_group_leave is called and the crash happens.

Any ideas are most appreciated! Thanks!

jestro
  • 2,524
  • 4
  • 27
  • 46

2 Answers2

28

If dispatch_group_leave call isn't balanced with dispatch_group_enter then crash may happen.

mustafa
  • 15,254
  • 10
  • 48
  • 57
  • Interesting. I have an enter before the first closure is called. hmmm. – jestro May 27 '15 at 07:18
  • 1
    I think this was it. Certain leaves were getting called too fast. Moved all the enters and the notify to before the leaves can be called. Thanks! – jestro May 28 '15 at 00:23
  • 5
    @mustafa is there a way to prevent the case of calling dispatch_group_leave more than it should? i.e., for cases that I can't tell for sure that completion block - of which in it the dispatch_group_leave is called - will not be called more than once? – ofer2980 Oct 09 '16 at 13:06
  • @ofer2980 did you find a way? – hyouuu Jun 03 '18 at 19:22
  • We can add a little bit sleep thread call after dispatch_group_leave. It will help dispatch_group to apply concurrency rules. It saved my day. – Mohd Haider May 01 '20 at 10:02
8

In the worst case, you can check the discount group's count via its debugDescription String:

let count = self.groupExecuting.debugDescription.components(separatedBy: ",").filter({$0.contains("count")}).first!.components(separatedBy: CharacterSet.decimalDigits.inverted).filter({Int($0) != nil})
assert(count.first != "0")

This strategy is further explored in this question: DispatchGroup: check how many "entered"

pkamb
  • 33,281
  • 23
  • 160
  • 191
Bhavesh Sarwar
  • 166
  • 2
  • 2