0

I have multiple api's in a controller and after successful response I have to reload the UITableView.

For now I started with two api having second api dependency on first one using BlockOperation and DispatchGroup in it.

First in viewDidLoad:

getDataFromAllApis {
    self.tableView.reloadData()
}

Then I added the method:

func getDataFromAllApis(completion: @escaping (() -> Void)) {

    let queue = OperationQueue()

    let getFirstDataOperation = BlockOperation {
        let group = DispatchGroup()
        group.enter()
        self.getFirstDataFromApi {
            group.leave()
        }
        group.wait()
    }
    queue.addOperation(getFirstDataOperation)

    let getSecondDataOperation = BlockOperation {
        let group = DispatchGroup()
        group.enter()
        self.getSecondDataFromApi {
            group.leave()
        }

        group.notify(queue: .main) {
            completion()
        }
    }
    queue.addOperation(getSecondDataOperation)

    getSecondDataOperation.addDependency(getFirstDataOperation)
}

The problem that I am facing here is getSecondDataOperation executes first and returns to the tableview reload part.

Am I missing something here or there can be a different approach for it? Any help will be appreciated.

I have tried going through this post :

Amit
  • 4,837
  • 5
  • 31
  • 46

1 Answers1

5

You are way overthinking this. Just call the second API from the completion handler of the first API. No operations, no dispatch groups, no nothing.

self.getFirstDataFromApi {
    self.getSecondDataFromApi {
        // call the completion handler
    }
}

As for why your code didn't work, it's because you didn't do what the linked answer said to do!

How can you use Dispatch Groups to wait to call multiple functions that depend on different data?

It said to do this:

getSecondDataOperation.addDependency(getFirstDataOperation)
queue.addOperation(getFirstDataOperation)
queue.addOperation(getSecondDataOperation)

That isn't what you did. You did this:

queue.addOperation(getFirstDataOperation)
queue.addOperation(getSecondDataOperation)
getSecondDataOperation.addDependency(getFirstDataOperation) // too late

(However, that post, while ingenious, is not what I would do in this situation. If I wanted to sequentialize download operations, I would use the technique described here: https://fluffy.es/download-files-sequentially/. Or, in iOS 13, I'd use the Combine framework, as I describe here: https://stackoverflow.com/a/59889993/341994.)

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thank you for the answer. I did it first but I wanted to try it through dispatchgroup and blockoperation using dependencies as there can be more api's in the screen and the result gonna be to reload the table at the end. – Amit Jan 28 '20 at 16:02
  • OK, that's a good response. But it is not what you asked! You didn't ask for a _general_ solution; you asked about _this_ particular code not behaving as you desired, and I told you how to make it behave as you desired. You can solve the problem with DispatchGroup, but not the way _you_ were using it. And you certainly cannot do with BlockOperation as the operation finishes when you _launch_ the API call, not when the API call returns. – matt Jan 28 '20 at 16:06
  • I tried seeing the post which I mentioned in the question. Can you please tell me where did I missed it ? – Amit Jan 28 '20 at 16:27
  • I have edited my answer. You didn't do what that post said to do! – matt Jan 28 '20 at 16:28
  • Thank you for the pointing out that small mistake and for the Combine framework. One more thing, Is my approach wrong anywhere ? Why a downvote ? – Amit Jan 28 '20 at 16:43
  • That was my fault, I apologize. – matt Jan 28 '20 at 16:46