Consider the following code snippet. It creates a closure that prints out the value of the variable i. When it runs, should it print out 25, the value of the variable at the time the closure was created, or 35, the current contents of the memory pointed to by the variable reference?
var i = 25 var cl = {println(i)} i = 35 cl()
If you paste this snippet into a playground, you’ll find that this code prints 35, and not 25. That’s because Swift closures default to capturing references, not values. To change this behavior and capture the value, use a capture list, as in the following example.
var i = 25 var cl = {[i] in println(i)} i = 35 cl()
The use of [i] enables you to capture the value of i at the time you create the closure instead of at a later runtime.
Capture lists appear as the first item in a closure. They’re listed before any parameter clauses or identifier lists and require the in keyword to be used. For example, here’s another closure. This one is String -> Bool. It more or less does the same work as the previous closure but offers extra syntactic elements so you can see a capture list in a more complex setting.
var anotherClosure = { [i] (x : String) -> Bool in println(i) return true }
Here’s another example, one that uses a class instance instead of an integer.
class MyClass { var value = "InitialValue" } var instance = MyClass() // original assignment var cl2 = {[instance] in println(instance.value)} instance = MyClass() // updated assignment instance.value = "UpdatedValue" cl2()
If you omit the [instance] in capture list, this example prints out “UpdatedValue”, the value associated with the updated variable assignment. With the capture list, it prints “InitialValue”. This is the value stored by the original assignment.
When working with classes, a capture list can add modifiers to captured elements, specifically weak, unowned, unowned(safe) and unowned(unsafe). According to the reference material I’ve been reading, you most commonly see modifier usage when you want to capture self without reference cycles. The Swift Programming Language offers the following example. Here, the capture list enables you to capture the reference to self as an unowned — instead of strong — reference, avoiding reference cycles.
lazy var asHTML: () -> String = { [unowned self] in if let text = self.text { return "<\(self.name)>\(text)" } else { return "<\(self.name) />" } }
Thanks Lily B.
7 Comments
It’s hard to understand what is going on in the line var cl2 = {[instance] in println(instance.value)}
Does the closure have a deep copy of instance? That suggests some kind of reflection going on. It’s a bit head spinning.
Your article helped me understand some of what wasn’t working for me with NSUndoManager’s registerUndoWithTarget(_:handler:). As a thank you, I linked it from an answer I left for a Stack Overflow question whose answers weren’t exactly helping me. Between your article and the Swift book’s Expressions section, I got things working: http://stackoverflow.com/questions/24326984/how-do-i-register-nsundomanager-in-swift/32596899#32596899
[…] also: Capturing references in closures, Capture Lists, The __block Storage […]
Hey, Erica; lots of people don’t know that these are general decl modifiers:
class X { init(){} }
var a = X()
unowned var b = a
print(b)
a = X()
print(b) // trap
might be worth mentioning.
When you use [unowned self] are you creating a new variable of type self ? Or are you modifying the existing class/structure ?
You cannot test the above code on playground for some reason. Use a sample xcode project to see it happen.
This post is from 2014.