# Understanding Swift Closures

### Intro

The Swift documentation [provides](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures) a comprehensive introduction to Closures. However, in this session, we will cover some interesting aspects of Swift closures that are not fully covered in the documentation.

**DEFINITION**: Closures are self-contained blocks of functionality that can be passed around and used in your code.

Closures take one of three forms:

* Global functions and class/struct/enum methods are closures that have a name and don’t capture any values.
    
* Nested functions are closures that have a name and can capture values from their enclosing function.
    
* Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
    

**NOTE**: Function *is* a special case of closure.

**NOTE**: In the first two forms of closures listed above, the name actually refers to a function signature, which includes the function name and argument names.

The **closure** is a typed value and the type of closure is written like this:

`(parameter-tuple) -> return-value`

We can consider function declaration as a variable of closure type once the following are equivalent in Swift:

```swift
func isPositive(x: Int) -> Bool { return x > 0 }
let isPositive: (Int) -> Bool = { x in return x > 0 }
```

`{ param in ... }` - is called a **closure expression.**

**Closure expressions** can be considered as anonymous literals of closure type.

In the same way that `1234` and `"hello"` are **integer** and **string** literals. They’re also anonymous - they aren’t named. The only way they can be used is to assign them to a variable when they’re created, or to pass them to another function or method.

In the nutshell, closures provide a way to encapsulate a piece of functionality or behavior as a first-class object that can be passed around and used in different parts of your code.

### **How to create a reference cycle with closure?**

The most dangerous thing about the closures is that you can create a reference cycle using them. **Reference cycle** (also known as a **retain cycle**) occurs when two or more objects hold strong references to each other, preventing them from being deallocated even when they're no longer needed. This can lead to memory leaks and negatively impact the performance of your app.

Let’s consider an example:

```swift
class TestObject {
    var counter = 0
    var closure: () -> Void = {}

    deinit {
        print("No reference cycles!") // will never be called
    }
}

var object = TestObject()

object.closure = {
    object.counter += 1 // reference cycle is created
}
```

In this example, **object** holds the reference to the **closure** and **closure** captures the reference to the **object**. Object will never be deallocated and **deinit** will never be called.

Now that we have identified the problem, let's explore some solutions to fix it.

```swift
class TestObject {
    var counter = 0
    var closure: () -> Void = {}

    deinit {
        print("No reference cycles!") // will be called at the end of the scope
    }
}

var object = TestObject()

object.closure = { [weak object] in // or [unowned object]
    object?.counter += 1
}
```

Expression `[weak object]` in the begining of the closure is called a **capture list**.

Using a **capture list with a weak modifier** tells the closure that the object will be captured by weak reference to avoid retain cycle creation. Let’s take a look on the capture list more closely.

### **What is a capture list?**

When you define a closure, you can also specify a **capture list**, which tells the closure which variables and constants it should capture from the surrounding context.

**DEFINITION**: A capture list is simply a comma-separated list (or just an array) of variable or constant names, enclosed in square brackets, like this:

```swift
{ [variable1, variable2, variable3] in
	// class object variables will be captured by strong reference
    // closure code goes here
}
```

You can use **weak** or **unowned** modifiers to capture variables by weak or unowned reference correspondingly to prevent the retain cycle:

```swift
{ [weak variable1, unowned variable2] in
	// variable1 will be captured by weak reference
	// variable2 will be captured by unowned reference
    // closure code goes here
}
```

But what is the difference between **weak** and **unowned**?

### Weak vs unowned

To prevent a retain cycle, you can use either the `weak` or `unowned` modifier. However, `weak` is generally considered safer because if the referenced object is deallocated, the `weak` reference becomes nil. On the other hand, an `unowned` reference would result in a runtime error.

Typically, `unowned` is used when there is a one-to-one relationship between two objects, and both are expected to be deallocated at the same time. However, using `unowned` is similar to using **implicitly unwrapped optional**. If the object is nil, a crash will occur. In general, it is recommended not to use the `!` operator and this advice can be considered for `unowned` as well.

Even though `unowned` is faster and allows for immutability and non-optionality, `weak` is safer, and the performance gain from using `unowned` may not be as valuable, especially considering the risk of crashes. This is just my perspective, and ultimately, the choice of which modifier to use depends on the specific context and needs of the code.

### **Understanding capture lists**

The concept of a capture list may appear straightforward, but there are nuances to consider.

One example is when capturing a value type in a capture list. In this case, the value type will be copied into the closure.

```swift
func returnClosureWithCapturedInteger() -> () -> Void {
    var counter = 0

    let closure = { [counter] in // capture list
        print("counter =", counter)
    }

	counter = 1
    closure() // counter = 0
    counter = 2
    closure() // counter = 0
    counter = 3

    return closure
}

let closure = returnClosureWithCapturedInteger()
closure() // counter = 0
```

As demonstrated, even though we captured the value of the **counter** and later changed it, the captured value remained equal to 0 when the closure was called. You can say that this is expected because value types are copied every time they are passed to a new location. However, what happens if we do not include the value type in the capture list?

In this case, the behavior is not as straightforward as in the previous example:

```swift
func returnClosureWithoutCapturedInteger() -> () -> Void {
    var counter = 0

    let closure = { // nothing in capture list
        print("counter =", counter)
    }
		
    counter = 1
    closure() // counter = 1
    counter = 2
    closure() // counter = 2
    counter = 3

    return closure
}

let closure = returnClosureWithoutCapturedInteger()
closure() // counter = 3
```

What happened in this case? Even though we did not capture `counter` in the capture list, we still used it within the closure.

In this scenario, the closure captures a reference to enclosing function context and `counter` inside it as well so closure can use it within its own body. By capturing context by reference, the closure ensures that the `counter` does not disappear after the call to `returnClosureWithoutCapturedInteger` ends and `counter` remains available the next time the returned `closure()` is called. This means that when we change `counter` later and call the closure, the updated version of `counter` is printed, even though it should not exist anymore as a local variable.

### What about capturing reference type?

When it comes to reference types, the outcome will be the same regardless of whether you include them in the capture list or not. However, it's recommended to capture reference types in the capture list as it's the only way to resolve any reference cycles that may be created when capturing reference values. As mentioned earlier, it's advisable to always use a capture list with a weak or unowned modifier to prevent reference cycles and ensure safe memory management.

### Understanding escaping/non-escaping

When closures are passed as arguments to a function, they need to be marked as `@escaping` to indicate the possibility of reference cycles. This annotation serves as a warning to the developer using the function. If closure is stored to be called later, it is considered **escaping**, while closures that don't leave the function's local scope are **non-escaping**. When using escaping closures, the compiler requires explicit usage of `self` in closure expressions to prevent unintentional strong capturing of self, which can cause reference cycles. Non-escaping closures cannot create permanent reference cycles since they are automatically destroyed when the function they're defined in returns.

By default, closures passed as function arguments are **non-escaping**. Remember that this default only applies to function parameters, and functions used as parameters in tuples or optionals are automatically marked as **escaping**. Therefore, a function that takes a function argument where the parameter is both optional and non-escaping cannot be written.

**NOTE**: `@escaping` is explicit signal of potential creating of reference cycles

### Nested functions

As was already mentioned, **nested functions** are closures as well. This means the nested function captures variables from the surrounding context as well.

```swift
func returnNestedFunction() -> () -> Void {
    var counter = 0

    func nestedFunc() -> Void {
        print("counter =", counter)
    }

    counter = 1
    nestedFunc() // counter = 1
    counter = 2
    nestedFunc() // counter = 2
    counter = 3

    return nestedFunc
}

var nestedFunc = returnNestedFunction()
nestedFunc() // counter = 3
```

As you can see nested function works in the same way as closures **without capture list**. Nested function captures a reference to enclosing function context so when we change `counter` later and call the closure, the updated version of `counter` is printed.

### Unobvious cases of retain

Capturing the object in closure not the only way you can introduce reference cycle in your code.

```swift
class AlertView {
    var buttonTapped: (() -> Void)?
}

class ViewController {
    let alert: AlertView

    init() {
        alert = AlertView()
        alert.buttonTapped = buttonTapped // self will be captured!!!
    }

    func buttonTapped() {}

    deinit {
        print("No reference cycles!") // Will never be called
    }
}

let vc = ViewController()
```

The `alert.buttonTapped = buttonTapped` line looks like an innocent assignment, but beware: we’ve just created a reference cycle! Every reference to a method of an object (like `buttonTapped` in the example) implicitly captures the method's self object.

When the `AlertView` object calls the closure that’s stored in its buttonTapped property, the property must somehow know which object’s instance method it needs to call - it’s not enough to just store a reference to `ViewController.buttonTapped` method without referencing the instance. If `ViewController` object will be deallocated at some moment `AlertView` object will lose access to the method. This is why it captures the self in this case.

Under the hood, instance methods are modeled as closures that, given an instance, return another closure that then operates on the instance. Implicit type of the expression `ViewController.buttonTapped` is actually `(ViewController) -> (Int) -> ()`.

And `vc.buttonTapped` is actually just another way of writing `ViewController.buttonTapped(vc)`.

Both expressions return a closure of type `(Int) -> ()`, and this closure strongly captures the `vc` instance.

In this scenario, to avoid a strong reference retaining, you need to wrap the method call in another closure that captures the object weakly:

```swift
alert.buttonTapped = { [weak self] index in
    self?.buttonTapped(atIndex: index)
}
```

### Is closure reference or value type?

In Swift, reference types are not limited to classes only. Functions and closures are also considered reference types.

Unlike value types, which are stored in the stack, reference types are stored in the heap. Hence, closures are also stored in the heap. Additionally, any captured value type is moved to the heap so that the closure can access it for the duration of its lifetime.

```swift
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}
```

This is an example from the Swift book and as you can already guess:

* `incrementer` as a closure and it will be stored in the heap.
    
* `runningTotal` is a value type but it will be moved to the heap as well.
    

### Recap

* Closures are blocks of functionality that can be passed around and used in your code;
    
* Function *is* a special case of closure;
    
* You can create a retain cycle using closures;
    
* You can use capture list and weak/unowned modifiers to prevent a retain cycle.
    
* Closure can catch value type by reference or copy it;
    
* `@escaping` is an explicit signal of potential creating of reference cycles;
    
* Nested functions are closures as well;
    
* You should be careful with assigning a class method to closure because it retains the class object as well;
    
* Closure is a reference type.
    

### Conclusion

Overall, closures are powerful and essential tool for Swift developers, and understanding how to use them effectively can significantly reduce problems that can be introduced in your app in process of development.

Even though we discussed a lot about closures in this post, there are still a lot of things we didn’t cover that you can read about like for example [multiple trailing closures](https://www.hackingwithswift.com/swift/5.3/multiple-trailing-closures)(**Swift 5.3**) and [autoclosures](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/#Autoclosures).

### Links

[https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/)
