How do I correctly handle & complete this function that takes in an @escaping function correctly?

Viewed 36

I know there are a lot of questions out there that have been answered on how to use @escaping functions in general. My issue is a bit more niche as I am working with an API that gives me a function that takes in an @escaping function (or so I think). I need help decoding both (1) the function declaration I am working with and what it means and (2) how I write a function to effectively call it, and complete it and be able to exit.

The API function is declared as so (with some stuff hidden), wrapped in a larger struct, i'll call specialStruct:

public func context(completion: @escaping ((Result<String, SpecialClassError>) -> Void)) {
    class.something() { result in
        switch result {
            case .success(let response):
                completion(.success(response.cid))
            case.failure(let error):
                completion(.failure(.network(error: error), data: nil)))
        }
    }
}

Currently, I am running this:

specialStruct.context(completion: {result in 
    switch result {
        case .success(let str):
            let _ = print(str)
        case .failure(let error):
            let _ = print(error.localizedDescription)
    }
})

This is what happens as I step through my handler, which is a bit confusing to me: It is wrapped in an init() in a SwiftUI View. It goes through once at the start, but doesn't actually step into context? It seems to start, but doesn't do anything with result.

  1. Code keeps running...eventually comes back to my call at case .success(let str):.
  2. Runs the next line, and this successfully prints the expected value from the API after connecting to it. let _ = print(str)
  3. Goes to end of call line at bottom })
  4. Which brings me back to the context() declaration shown above, at completion(.success(response.cid))
  5. Jumps to the second to last } in the function declaration.
  6. Jumps into the something() call, specifically a line that is completion(.success(decoded))
  7. Continues in something() call, eventually landing back at an Apple Module FPRNSURL...nInstrument and line 307 completionHandler(data, response, error);
  8. Here it stays for good.

Let me know if that made it more confusing that it needs to be! Thanks!

EDIT: Added a note that in step (2) above, the API has already been connected to and returned the expected value. For some reason it goes back to the completion handler and gets hung up, even though I am already done.

1 Answers

The steps you wrote exactly describes Asynchronous API calls, this is the expected behavior as the api takes time to give you the requested result & Swift won't wait until it does..

Also, in the function context, you don't need all that code, you can simply do:

public func context(completion: @escaping ((Result<String, SpecialClassError>) -> Void)) {
    class.something() { result in
        completion(result)
    }
}
Related