From Swift Programming Guide - Closures
A closure can capture constants and variables from the surrounding context in which it’s defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
A closure captures variables, not the contents of variables. When we are talking about local variables in a function (which are normally allocated on stack), it makes sure they are accessible even when the function exits and other local variables are deallocated, therefore we can do things like this:
func myFunc() {
var array: [Int] = []
DispatchQueue.main.async {
// executed when myFunc has already returned!
array.append(10)
}
}
Your example is similar. The closure captures the variable. This is a variable on module level, therefore its scope always exists. When you reassign its value, it will affect the value read inside the closure.
Or, in other words, the closure will be equivalent to:
var closure = {
print(CurrentModule.element?.name ?? "default value")
}
where CurrentModule is the name of your main module (which is usually the name of your project).
To prevent this behavior and capture the value of the variable instead, we can use closure capture list. Unfortunately, the official documentation does not properly explain what exactly is a capture list. Basically, using a capture list you declare variables local to the closure using values that are available when the closure is created.
For example:
var closure = { [capturedElement = element] in
print(capturedElement?.name ?? "default value")
}
This will create a new variable capturedElement inside the closure, with the current value of variable element.
Of course, usually we just write:
var closure = { [element] in
print(element?.name ?? "default value")
}
which is a shorthand for [element = element].