I am making API calls and for that purpose I use completionHandlers in Swift. I came to issues where I need to call one function with completionHandler right after another one succeeds but the nested function is not called and main function does not return anything now.
Here is code:
func submit(completionHandler: @escaping (Result<MyResult, Error>) -> Void) {
submitSerice.subit() { [weak self] result in
switch result {
case .success(let submitResponse):
self?.getNextSession() { response in
switch sessionResponse {
case .success(let nextSession):
// do something and return submitResponse
completionHandler(.success(submitResponse))
case .failure(let error):
completionHandler(.failure(error))
}
}
case .failure(let error):
completionHandler(.failure(error))
}
}
}
func getNextSession(completionHandler: @escaping (Result<NextSession, Error>) -> Void) {
print("Calling getNextSession()")
nextSesssionService.nextSession() { result in
switch result {
case .success(let response):
completionHandler(.success(response))
case .failure(let error):
completionHandler(.failure(error))
}
}
}
When getNextSession and submit are called alone everything works fine but here print "Calling getNextSession()" is not even shown in terminal.
Given how you've written this, a likely cause is that self
is deallocated between the time you call submit
and the time submitSerice.subit
calls its completion handler. If you want to ensure that this operation completes, you should not use [weak self]
here. You should hold a strong reference to ensure the operation completes. At a minimum, you should probably add logging if self
is nil so that you know what's happened.
That said, I highly recommend converting this to async/await
. The code to handle serial execution of asynchronous operations will be dramatically simpler than when using completion handlers.