[Swift] Capture list

What is this post?

This is an original translation of the Official Document Content for the capture list in Swift programming.

environment

macOS 10.15.7 Xcode 12.1 Swift 5.3

What is a capture list?

By default, closure expressions capture "constants and variables in their surrounding scope" with ** strong references **. Capture lists allow you to explicitly control how closures capture values.

The capture list is described as a "comma-separated list enclosed in square brackets" before the list of parameters. When using a capture list, always use the ʻin` keyword, even if you omit the parameter name, parameter, and return types.

{ [value1, value2, ...] in STATEMENT }

The capture list entries are initialized when the closure is created. The constant for each entry in the capture list is initialized to the value "Constant or variable with the same name in the surrounding scope". For example, in the code below, ʻa is included in the capture list, but b` is not.

python


var a = 0
var b = 0
let closure = { [a] in    //a is initialized with 0
    print(a, b)           //Changing a outside the scope has no effect
}

a = 10                    //This change does not affect a in the capture list
b = 10
closure()
// Prints "0 10"

In-scope ʻas are initialized with "out-of-scope ʻa values" when the closure is created, but those values are not specifically connected. That is, changing an out-of-scope ʻa does not affect an in-scope ʻa, and a change to an in-closure ʻa does not affect an out-of-closure ʻa. In contrast, there is only one variable named b outside the scope, so that change affects both inside and outside the closure.

However, this is not the case if the captured variable was "reference type data". For example, in the code below, there are two xs in" Variables out of scope "and" Constants in scope ", but both refer to the same object because they are reference type data.

python


class SimpleClass {
    var value: Int = 0
}
var x = SimpleClass()          //The first variable x (x.value is initialized to 0)
var y = SimpleClass()
let closure = { [x] in         //The second constant x (x).value is initialized to 0)
    print(x.value, y.value)    //Changing x outside the scope has an effect
}

x.value = 10                   //Out-of-scope changes also affect x in the capture list
y.value = 10
closure()
// Prints "10 10"

If the value type of an expression is a class, you can mark the expression with weak in the capture list to capture a" weak reference "to the value of the expression. You can also mark an expression with ʻunowned` in the capture list to capture an" unowned reference ".

python


myFunction { print(self.title) }                    //Capturing values with "strong references" (implicit)
myFunction { [self] in print(self.title) }          //Capturing values with "strong references" (explicit)
myFunction { [weak self] in print(self!.title) }    //Capturing values with "weak references"
myFunction { [unowned self] in print(self.title) }  //Capture values with "unowned references"

You can also name the values in the capture list and bind any expression. The "bound expression" is evaluated when the closure is created and the value is captured with the specified intensity. For example:

python


// "parent"As a weak reference"self.parent"To capture
myFunction { [weak parent = self.parent] in
    print(parent!.title) 
}

For more information and examples of closure expressions, see Closure Expressions (https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID95). For more information and examples of capture lists, see Resolving strong closure reference cycles (https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html#ID57).

Recommended Posts

[Swift] Capture list
[Swift5] Start ARKit ~ Motion capture ~
Thread-safe list
List method
[Swift] Closure
Work list
Link list