SwiftUI For Dummies
Book image
Explore Book Buy On Amazon
One important feature in Swift is closure. Closures are self-contained blocks of code that can be passed to functions to be executed as independent code units. Think of a closure as a function without a name. In fact, functions are actually special cases of closures.

SwiftUI app development ©Shutterstock/NDAB Creativity

Swift offers various ways to optimize closures so that they’re brief and succinct. The various optimizations include the following:

  • Inferring parameter types and return types
  • Implicit returns from single-statement closures
  • Shorthand argument names
  • Trailing closure syntax
  • Operator closure

Understanding Swift closures

The best way to understand Swift closures is to use an example. Suppose you have the following array of integers:
let numbers = [5,2,8,7,9,4,3,1]
Assume you want to sort this array in ascending order. You could write your own function to perform the sorting, or you could use the sorted() function available in Swift. The sorted() function takes two arguments:
  • An array to be sorted
  • A closure that takes two arguments of the same type as the array and returns a true if the first value appears before the second value

Using Swift functions as closures

In Swift, functions are special types of closures. As mentioned, the sorted() function needs a closure that takes two arguments of the same type as the array, returning a true if the first value appears before the second value. The following Swift function fulfils that requirement:
func ascending(num1:Int, num2:Int) -> Bool {
    return num1
The ascending() function takes two arguments of type Int and returns a Bool value. If num1 is less than num2, it returns true. You can now pass this function to the sorted() function, as shown here:
var sortedNumbers = numbers.sorted(by: ascending)
The sorted() function now returns the array that is sorted in ascending order.

The sorted() function does not modify the original array. It returns the sorted array as a new array.

Assigning Swift closures to variables

As mentioned earlier, functions are special types of closures. In fact, a closure is a function without a name. However, you can assign a closure to a variable — for example, the ascending() function discussed earlier can be written as a closure assigned to a variable:
var compareClosure : (Int, Int)->Bool =
    {
        (num1:Int, num2:Int) -> Bool in
            return num1 < num2
    }
To use the compareClosure closure with the sorted() function, pass in the compareClosure variable:
sortedNumbers = numbers.sorted(by: <strong>compareClosure</strong>)

Writing Swift closures inline

You can pass a function into the sorted() function as a closure function, but a better way is to write the closure inline, which obviates the need to define a function explicitly or assign it to a variable.

Rewriting the earlier example would yield the following:

sortedNumbers = numbers.sorted(by:
    {
        (num1:Int, num2:Int) -> Bool in
            return num1 < num2
    }
)
As you can see, the ascending() function name is now gone; all you’ve supplied is the parameter list and the content of the function.

If you want to sort the array in descending order, you can simply change the comparison operator:

sortedNumbers = numbers.sorted(by:
    {
        (num1:Int, num2:Int) -> Bool in
            return num1 > num2
    }
)

Understanding type inference

Because the type of the first argument of the closure function must be the same as the type of array you’re sorting, it’s actually redundant to specify the type in the closure, because the compiler can infer that from the type of array you’re using:
var fruits = ["orange", "apple", "durian",
              "rambutan", "pineapple"]
print(fruits.sorted(by:
    {
        (fruit1, fruit2) in
            return fruit1
If your closure has only a single statement, you can even omit the return keyword:
print(fruits.sorted(by:
    {
        (fruit1, fruit2) in
            fruit1

Using shorthand argument names

Above, names were given to arguments within a closure. In fact, this is also optional, because Swift automatically provides shorthand names to the parameters, which you can refer to as $0, $1, and so on.

The previous code snippet could be rewritten as follows without using named parameters:

print(fruits.sorted(by:
    {
        $0<$1
    })
)
To make the closure really terse, you can write everything on one line:

print(fruits.sorted(by:{ $0<$1 }))

Working with Swift’s operator function

You saw that the closure for the sorted() function was reduced to the following:
print(fruits.sorted(by:{ $0<$1 }))
One of the implementations of the lesser than (<) operator is actually a function that works with two operands of type String. Because of this, you can actually simply specify the < operator in place of the closure, and the compiler will automatically infer that you want to use the particular implementation of the < operator. The preceding statement can be reduced to the following:
print(fruits.sorted(by:<strong><</strong>))
If you want to sort the array in descending order, simply use the greater than (>) operator:
print(fruits.sorted(by:<strong>></strong>))

Using trailing closures in Swift

Consider the closure that you saw earlier:
print(fruits.sorted(by:
    {
        (fruit1, fruit2) in
            return fruit1
Notice that the closure is passed in as a second argument of the sorted() function. For long closures, this syntax may be a little messy. If the closure is the final argument of a function, you can rewrite this closure as a trailing closure. A trailing closure is written outside of the parentheses of the function call. The preceding code snippet, when rewritten using the trailing closure, looks like this:
print(fruits.sorted()
    {
        (fruit1, fruit2) in
            return fruit1
Using the shorthand argument name, the closure can be shortened to the following:
print(fruits.sorted()<strong>{$0<$1}</strong>)

Want to learn more? Check out our SwiftUI Cheat Sheet.

About This Article

This article is from the book:

About the book author:

Wei-Meng Lee is founder of Developer Learning Solutions, specializing in hands-on technology training. His name regularly appears in publications like DevX.com, MobiForge.com, and CODE Magazine. He is also the author of SwiftUI For Dummies, Beginning Swift Programming, Python Machine Learning, and Learning WatchKit Programming.

This article can be found in the category: