Search code examples
iosmultithreadingdownloadsequential

GCD: Making Sequential Download Calls; ONE BY ONE


SCENARIO

The app downloads user subscriptions one by one. This call will be made in multiple places (in completion block after another network call and from a button press from a UIAlertController). The logic is to download all the subscriptions and once one subscription download is down it goes to the next until all have been downloaded and then our SVProgressHUD dismisses. The code works great when we build and run from Xcode. But when we build the IPA and send to our customer, this logic creates some sort of a stall, and the SVProgressHUD alert keeps spinning:

enter image description here

This is a big problem because our application is focused around downloading content from subscriptions.

Why is this logic stalling after I Archive and build an IPA from it, but not when I build and run from Xcode?

Code Below:

// Making the call 

    DispatchQueue.main.async {
        DGWebService().syncUserSubscribedContent {
            DispatchQueue.main.async {
                self.finishLogin()
            }
        }
    }

// Sequentially going through each subscription and downloading them

    func syncUserSubscribedContent(completion: @escaping Constants.WebService.ContentCompletion) {
        let subscriptions = MPTUser.sharedUser.getSubscriptionsForDownload()
        DispatchQueue.global().async {
            if subscriptions.count > 0 {
                var index:Int = 0
                var t = subscriptions.count
                var downloading: Bool = false
                while t != 0 {
                    if downloading == false {
                        downloading = true
                        if index < 0 {
                            index = 0
                        }
                        if index > subscriptions.count - 1 {
                            index = subscriptions.count - 1
                        }
                        if index <= subscriptions.count {
                            let subscription = subscriptions[index]
                            if subscription.didDownloadContent == false {
                                if let subscriptionID = subscription.subscriptionID {
                                    DispatchQueue.main.async {
                                        SVProgressHUD.show(withStatus: "Downloading Documents\nfor\n\(subscription.functionalGroupName!)\n\(index+1) of \(subscriptions.count)")
                                    }
                                    self.getUserSubscribedContent(subscriptionID: subscriptionID, completion: { (success) in
                                        subscription.didDownloadContent = true
                                        index += 1
                                        t -= 1
                                        downloading = false
                                    })
                                }
                                else {
                                    index += 1
                                    t -= 1
                                    downloading = false
                                }
                            }
                        }
                        else {
                            index += 1
                            t -= 1
                            downloading = false
                        }
                    }
                }
            }
            completion()
        }
    }

self.getUserSubscribedContent is a function that downloads the content and sends a completion back in the block.

If someone could help me out here it would be much appreciated.


Solution

  • You can try using a DispatchGroup. Here's a rough (and untested) example:

    DispatchQueue.global().async {
        let subscriptions = MPTUser.sharedUser.getSubscriptionsForDownload()
        let group = DispatchGroup()
        var completed = 0
        let completion: (Bool) -> Void = {
            if $0 {
                completed += 1
            }
            group.leave()
            DispatchQueue.main.async {
                SVProgressHUD.show(withStatus: "Downloading Documents\nfor\n\(subscription.functionalGroupName!)\n\(completed) of \(subscriptions.count)")
            }
        }
        for subscription in subscriptions {
            self.getUserSubscribedContent(subscriptionID: subscription.subscriptionID, completion: completion)
            group.enter()
        }
        // However long you want to wait (in seconds) before timing out
        _ = group.wait(timeout: .now() + 30)
    }