Reputation: 13043
This is my code:
class Person {
let age: Int
init(age: Int) {
self.age = age
}
func callAgePrinter() {
// THIS LINE
AgePrinter.printAgeOf(person: { return self } )
}
}
class AgePrinter {
static func printAgeOf(person: () -> (Person)) {
print(person().age)
}
}
Person(age: 1).callAgePrinter()
Notice the comment: // THIS LINE
I am able to transform this line:
AgePrinter.printAgeOf(person: { return self } )
To:
AgePrinter.printAgeOf(person: { [unowned self] in return self } )
The result of the code is the same.
I am wondering: for nonescaping closures (which apply for Swift 4.2 only at function declaration level), what is the use a capture list? It is guaranteed for nonescaping closures that after the method is ended in which the closure is (or may not) be called, the closure is gone and not stored.
Ofcourse, a retain cycle can still occur when storting the output of the closure in my example. However, a capture cycle does not prevent this.
What difference does it make to include (or not include) a capture list in nonescaping closures?
Upvotes: 2
Views: 62
Reputation: 299355
It is common to use capture lists for self
, but that is not their only purpose. A capture list captures arbitrary values. And by "capture," I mean "makes its own shadow copy rather than closing over the value in its scope." Consider the following code:
var a = 10
let f: () -> Void = { print("f: \(a)") }
let g: () -> Void = { [a] in print("g: \(a)") }
a = 20
f() // f: 20; using "a" from the local scope surrounding f()
g() // g: 10; using "a" that was copied into g()
As a slightly more complex example, consider the following (incorrect) code where we accumulate some actions to perform, using some value that needs to increment from action to action:
var actions: [() -> Void] = []
var opId = 0
if someCase {
opId += 1
actions.append({ doSomethingWith(opId) })
}
if anotherCase {
opId +=1
actions.append({ doSomethingElseWith(opId) })
}
//...
actions.forEach { $0() }
This code is incorrect; all of the closures will have the same opId. However, if we add a capture list, we can resolve the problem:
actions.append({ [opId] in doSomethingWith(opId) })
Upvotes: 3
Reputation: 27221
Capture copies the information inside the variable inside a new one. I mean [unowned self]
creates another self
variable which is not actually a self
.
Upvotes: 2