Closure in Swift programming

Magical magician

After a long time I finally managed myself to start to writing again. Today I want to talk about one of my favorite features in Swift programming: closures. Closures are self-contained blocks of code that can be passed around and used in your code. They are very similar to functions, but they have some advantages that make them very powerful and expressive.

One of the advantages of closures is that they can capture values from the context where they are defined. This means that you can access variables and constants that are outside of the closure scope, even if they are no longer in scope when the closure is executed.

For example, look at this code:

closure.swift
var message = "Hello, awesome iOS Developer!"

let sayHello = {
  print(message)
}

messsage = "So long and goodbye, Objective-C"

sayHello()

This code defines a variable message and assigns it a string value. Then it defines a closure sayHello that prints the value of message. Then it changes the value of message to a different string. Finally, it calls the closure sayHello.

What do you think will be printed?

If you guessed “So long and goodbye, Objective-C”, you are wrong. The correct answer is “Hello, awesome iOS Developer!”. This is because the closure captured the value of message when it was defined, not when it was executed. So even though the value of message changed later, the closure still remembers the original value.

This feature of closures is very useful when you want to create a function that remembers some state or data from its creation time. For example, you can use closures to create custom comparators for sorting arrays, or custom animations for views, or custom actions for buttons.

Concise and elegant

Another advantage of closures is that they have a concise and elegant syntax that makes them easy to write and read. Swift has several rules that allow you to omit some parts of the closure expression, such as the parameter types, the return type, and the keyword return. For example, look at this code:

closure.swift
let numbers = [1, 2, 3, 4, 5]

let doubled = numbers.map({ (number: Int) -> Int in
    return number * 2
})

print(doubled)

This code above defines an array of numbers and uses the map method to create a new array with each element doubled. The map method takes a closure as an argument that defines how to transform each element of the original array. The closure has one parameter named number of type Integer and returns an Integer value.

The code above works perfectly fine, but it can be simplified by using some of the closure syntax rules. First, we can omit the parameter type and the return type, because Swift can infer them from the context. Second, we can omit the keyword return, because Swift automatically returns the single expression in the closure body. Third, we can use shorthand argument names instead of explicit parameter names. Fourth, we can use trailing closure syntax to write the closure outside of the parentheses of the map method call. The results is like this:

closure.swift
let numbers = [1, 2, 3, 4, 5]

let doubled = numbers.map { $0 * 2 }

print(doubled)

As you can see, this code above is much shorter and cleaner than the original one. It still does the same thing: it creates a new array with each element doubled. But it does so with less boilerplate and more clarity.

Closures are very powerful and expressive tools in Swift that allow you to write concise and elegant code. They can capture values from their context and use them later. They can also have simplified syntax that makes them easy to write and read.

I hope you enjoyed this article and have a new insight about closures in Swift. Stay tuned for more Swift topics in my next post. Probably 🥹


Visit my iOS Development course (delivered in Bahasa Indonesia) at iSwift eCourse

If you want to start your own career as an Indie iOS Developer, then this course was for you: Professional iOS Development

Email icon representing an email newsletter

Don't subscribe