0

What is the benefit of using a dispatch group with calls in the loop? I am using alamo fire as my network layer. The scenario is that I want to fetch data from the server in chunks and once all calls are done I can move forward. Do I really need to use dispatch group or simple looped calls will work?

for _ in 1...calls {
            callFetchTransaction(offset: self.offset, limit: self.transactionsLimit, calls: calls)
        }

and this is what is inside my function:

var listOfIdsToSort = [String:Date]()
func callFetchTransaction(offset:Int,limit:Int,calls:Int) {
    TransactionsModel.reportTransactions(offset: offset, limit: limit, success: { (transactions) in
        ACTIVITYCALL += 1
        print("CurrentOffset \(offset), with limit\(limit)")
        print("ACTIVITY CALL \(ACTIVITYCALL)")
        for transaction in transactions {
            self.listOfIdsToSort[transaction.id!] = transaction.createdAt!
        }
        if ACTIVITYCALL == calls {
           TransactionsModel.assignSequenceNumbers(dictOfIds: self.listOfIdsToSort) {
                self.didCompleteProgressAndSync(duration: 2.0)
                print("sync time after --- \(Date().timeIntervalSince1970)")
            }
            return
        } else if ACTIVITYCALL < calls {
            self.currentSyncingProgress += self.perActivityPercentage
            DispatchQueue.main.async {
                self.updateProgressBar(value: self.currentSyncingProgress)
            }
        }
    }) { (response, statusCode) in
        self.callFetchTransaction(offset: offset, limit: limit, calls: calls)
    }
 

It seems to work fine but I want to know if there are some benefits of dispatch group or flaws in this approach.

  • 2
    The asynchronous tasks can complete in any order. Using a dispatch group provides an easy way of knowing when all tasks are complete without the risks of race conditions that you have with concurrent access to a local variable. – Paulw11 Feb 23 '21 at 10:15
  • 1
    A `DispatchGroup` with corresponding `enter()` & `leave()` will let you know on `notify()` when ALL calls are completed, which you can't do with a simple "for loop". That's big advantage. – Larme Feb 23 '21 at 10:17
  • 1
    Custom logic of yours `ACTIVITYCALL += 1` and checking `ACTIVITYCALL == calls` for every API response calls all these cumbersome logics can be avoided with simple 3 or 4 statements of dispatch group, Also you are checking all these conditions only in success closure what if API fails ? Then you if condition `ACTIVITYCALL == calls` will never be satisfied :) Can you achieve what you can achieve very easily with dispatch group using loops or by blocking threads probably you can, should you do it? Never. Use dispatch group it is intended for monitoring completion of async tasks – Sandeep Bhandari Feb 23 '21 at 10:25
  • So eventually in this case it is syntactic sugar and will replace my customized logic. right? – Syed Meesum Ali Feb 23 '21 at 10:27
  • 2
    It's not just syntactic sugar. It is part of Grand Central Dispatch; a comprehensive concurrency framework from Apple. Concurrency is hard and it is easy to have problems with race conditions, deadlocks etc. It is much better to use the proven tools provided by the platform than to try and roll your own. – Paulw11 Feb 23 '21 at 10:45
  • 1
    When I said all your cumbersome custom logic can be avoided, I never said your logic will work flawlessly, your variable ACTIVITYCALL is not thread safe, so when multiple asynchronous tasks try to update it simultaneously there will/might be race condition as suggested by pawl, with your logic probably you will end up writing a blunt solution that will work most of the time but not always, use dispatch group instead n avoid all the pitfalls – Sandeep Bhandari Feb 23 '21 at 11:32

0 Answers0