What is Trailing closure in Swift?

What is Trailing closure in Swift?

As per the standard definition, Closures are self-contained blocks of functionality that can be passed around and used in your code.

When passing a closure expression to a function as the function’s final argument, it can be useful to write a trailing closure.

Trailing closure is written after the function call’s parentheses even though it is still an argument to the function. When you use the trailing closure syntax, you don’t write the argument label for the closure as part of the function call.

Syntax

//Note: This function accepts a closure as it's final argument
func functionName(closure: () -> Void) {
    // function body goes here
}

// Calling this function without using a trailing closure:

functionName(closure: {
    // closure's body goes here
})

// Calling this function with a trailing closure:

closure() {
    // trailing closure's body goes here
}

Note: 1. When using the trailing closure syntax, we don’t write the argument label for the first closure as part of the function call.

  1. A function call can include multiple trailing closures.

  2. The parameters to functions and closures are always constants.

Examples

Swift’s standard library provides a method called sorted(by:), which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sorted(by:) method returns a new array of the same type and size as the old one, with its elements in the correct sorted order.

//Calling sorted function without trailing closure
ascending = salaries.sorted(by: {s1: Int, s2: Int) -> Bool in
    return s1 < s2
})

//Calling trailing function with closure
ascending = salaries.sorted() { s1, s2 in s1 < s2 }

//Since closure is the only argument here, paratheses can be dropped as:
ascending = salaries.sorted {s1, s2 in s1 < s2 }

//Using shorthand arguments (explained previously):
ascending = salaries.sorted {$0 < $1}

In this example, we see how writing trailing closures, especially when the closure expression is long can make the code more readable.

In the next example, we understand how to use multiple trailing closures. The function makes a network call using the given URL and based on the outcome, the respective trailing closure is used.

//Example using multiple trailing closures

//Function call that makes an API call and returns result only if the API call is successful
func triggerAPICall(from url: URL, completion: (Result)->Void, onFailure: ()->Void) {
//make API call from given URL
...
if let result.status = .success {
completion(result)
} else {
onFailure()
}
}

//Calling the function above:
triggerAPICall(from: url) { result in 
///parse result and reload view
...
} onFailure: {
print("Oops! Something went wrong")
}

Writing the function this way lets you cleanly separate the code that’s responsible for handling a network failure from the code that updates the user interface after a successful download, instead of using just one closure that handles both circumstances.

Conclusion

Trailing closures are commonly used as completion handlers, i.e. to handle completion of network calls (as explained in the example above) and other such tasks. To know more about escaping, non-escaping closures, capture lists, etc. continue reading this article series. Till then,

Eat. Sleep. Swift Anytime. Repeat.