2

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.

J Smooth
  • 29
  • 1
  • 4
  • and where is a problem? – Asperi Jul 21 '22 at 14:05
  • 1
    "It is wrapped in an init() in a SwiftUI View." this is almost definitely not where you want to be doing this. SwiftUI views are created every time the view hierarchy is updated, the init method is not a place to kick off an asynchronous task. – jrturton Jul 21 '22 at 14:18
  • Where would you recommend I kick off this task then? It's needed because it pulls down a key that will let me further interact with an API and then populate a view. – J Smooth Jul 21 '22 at 14:27

1 Answers1

0

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)
    }
}
Timmy
  • 4,098
  • 2
  • 14
  • 34
  • I mean just how long should I expect to wait? I guess I didn't clarify in the post (will edit now), but the code & API returns the expected value at step (2) I outlined above...why does it keep going, and then still get hung up? It's already given me the value I need & connected to the API! How do I exit it? – J Smooth Jul 21 '22 at 14:29
  • How is it hanging? When the request is done it stops. It keeps going because it's asynchronous. check this out: https://stackoverflow.com/questions/36213948/what-is-the-difference-between-asynchronous-calls-and-callbacks – Timmy Jul 21 '22 at 16:40