Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

253
Views
Do we always need to call a completion handler inside a closure?

I have a completion handler that gets called inside my closure. However, the completion handler only gets called when everything goes well. In the case of an error, the completion handler never gets called.

func product(with id: String, _ completion: @escaping (Product) -> ()) {

     // Make a network request for the product
     ...

    if (product) {
       completion(product)
    }
}

Is this a bad design? I recently got the comment that completion handlers need to be called even in case of errors, otherwise the caller will be waiting indefinitely. I've never heard that before and now I'm wondering if this applies to Swift.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Strictly spoken the caller doesn't wait at all. The code in the closure will or will not be executed.

However it's good practice to return errors, too.

A smart way is the Result type

func product(with id: String, completion: @escaping (Result<Product,Error>) -> Void) {

     // Make a network request for the product
     ...
    if error = error { completion(.failure(error)); return }

    if product {
       completion(.success(product))
    } else {
       let error = // create some other error
       completion(.failure(error))
    }
}

And call it

product(with: "Foo") { result in
   switch result {
     case .success(let product): // do something with the product
     case .failure(let error): // do something with the error
   }
}

Note: The underscore character before completion in the function declaration is pointless.

over 4 years ago · Santiago Trujillo Report

0

If you will not call a completion nothing will happen 'cuz completion caller will not wait for it.

But if you want to cover all cases try to add a failure callback. For example:

func product(with id: String, _ success: @escaping (Product) -> (), failure: @escaping (Any) -> ())
over 4 years ago · Santiago Trujillo Report

0

In your case, if you are treating it as a completion, it means that it has to get called no matter what's case (success of failure with error), it has to returns when the process completed.

What you could do is to pass an optional error and product to the completion closure and then check whether the error is nil or not:

func product(with id: String, _ completion: @escaping (Product?, Error?) -> ()) {
    // in case of there is an error:
    completion(nil, error)
    return

    // if things went happy:
    completion(product, nil)
}

Calling the method:

product(with: "ID") { (product, error) in
    guard let returnedError = error else {
        print(product)

        return
    }

    print(returnedError)
}

Or:

product(with: "ID") { (product, error) in
    if let returnedError = error {
        print(returnedError)
        return
    }

    print(product)
}
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!