Completion Handlers in Swift

Aug 1, 2021 2 min read
Completion Handlers in Swift

Completion Handlers is not an easy concept if you are not good with closures. You can read the official docs here.

Why We Need Completion handler :

  • You’re executing a lengthy task in your code, like downloading a file, making a calculation, or waiting for a web service request.
  • You want to execute some code when the lengthy task is completed, but you don’t want to “poll” the task continuously to check if it’s finished.
  • Instead, you provide closure to the lengthy task, which it will call when the task is completed.

Make a Completion handler :

The completion parameter ask you to enter a closure block whose type is () -> () or () -> Void. So, let’s enter a closure block.

When working with completions, after your function is created, simply define the function and then when calling it and it autocompletes, hit enter. See an example here.

Example 1 | Returning Bool

Let's make a function which downloads data from server and after it completes its download it gives a notification to the user .

func downlaod(sucess:Bool,compleationHandler:(Bool)->Void) {
   for _ in 0...100 {
   		print("downloading data from sarver....")
   }
    
    compleationHandler(sucess)
}

in the above example that function will take 1 parameter which is of type Bool. Here's how to call it in another function or view:

let compleationhandler:(Bool)->Void = { (sucess) in
    if sucess {
    	print("Complete download data ")
    } else {
        print("Error")
    }
    
}

to implement the function you could do something like:

downlaod(sucess: true, compleationHandler: compleationhandler)

Example 2 | Void function

Let's say that you wanted to refresh some data and then perform some action. You can first initialize your function like so:

func fetchUserId(completion: @escaping () -> Void) {
        Amplify.Auth.fetchAuthSession { result in
            do {
                let session = try result.get()
                // Get user sub id
                if let identityProvider = session as? AuthCognitoIdentityProvider {
                    let usersub = try identityProvider.getUserSub().get()
                    DispatchQueue.main.async {
                        completion()
                    }
                }
            } catch {
                print("Fetch auth session failed with error - \(error)")
            }
        }
    }

and then you could use the newly refreshed data:

Button(action: {
    fetchUserId {
        print("Printed after data was reloaded")
    }
}) {
    Text("Tests")
}

Example 3 | Returning String

Using the same concept as above, you could return a string as follow:

func fetchUserId(completion: @escaping (String) -> Void) {
        Amplify.Auth.fetchAuthSession { result in
            do {
                let session = try result.get()
                // Get user sub id
                if let identityProvider = session as? AuthCognitoIdentityProvider {
                    let usersub = try identityProvider.getUserSub().get()
                    DispatchQueue.main.async {
                        completion(usersub)
                    }
                }
            } catch {
                print("Fetch auth session failed with error - \(error)")
            }
        }
    }

then you can use its value like so:

fetchUserId { completion in
    print(completion)
}

Example 4:

Here's another good example:

func loadHealthCareList(completionClosure: (indexes: NSMutableArray)-> ()) {
      //some code here
      completionClosure(indexes: list)
}
healthIndexManager.loadHealthCareList { (indexes) -> () in
            print(indexes)
}
Great! Next, complete checkout for full access to ArturoFM.
Welcome back! You've successfully signed in.
You've successfully subscribed to ArturoFM.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info has been updated.
Your billing was not updated.