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)
}