iosswiftcompletionhandler

Swift nested completionHandler


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.


Solution

  • 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.