I'm using Xcode6-beta2, but I've had the same issue since the very first public beta. My Swift subclass of Obj-C UIViewController looks like this:
class SomeVC: UIViewController { var c1: () -> () = { println(self) } var c2: () -> () { get { return { println(self) } } } var c3: () -> () { return { println(self) } } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) c1() c2() c3() } }
When the VC is shown, I see the following lines printed out:
(Function) <_TtC12SwiftiOSTest6SomeVC: 0x10bf1ed10> <_TtC12SwiftiOSTest6SomeVC: 0x10bf1ed10>
(c2 and c3 differ only in that it is not necessary to include the get {...} for a computed property if it is only gettable.)
So, the first closure's self seems to refer to the function/closure type itself, whereas the other ones' self refer to the view controller (as I would expect). The only difference between c1 and c2/c3 is that the former is a stored property, the latter are computed properties, but I would still expect the closures and their captured values be the same, i.e. self to always refer to the enclosing class. The way things are now, there seems to be no obvious way for the c1 closure to access methods / properties of the enclosing class.
Is this something documented somewhere (I read the Swift book and didn't find anything), or is it just a beta-compiler bug of some kind, which should be filed somewhere?
In Swift, closures capture the variables they reference: variables declared outside of the closure but that you use inside the closure are retained by the closure by default, to ensure they are still alive when the closure is executed.
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
Webpack, Babel, UglifyJS, and TypeScript are the most popular alternatives and competitors to Closure Compiler.
This looks interesting, so I dig little deeper. Found that, you can access the class instance variables within the closure like self.instanceVariable
. Then the closure will capture the self
within it. So now the self
refers to the class instance itself. Your closure should be a lazy property.
A lazy property means that you can refer to self within the default closure, because the lazy property will not be accessed until after initialization has been completed and self is known to exist.
You are missing @lazy so that self
is unknown to the closure thats why it is printing it as (Function)
my guess.
class TableViewController: UIViewController { var name = "anil" // Since swift 2.0 came out @lazy is replaced by lazy lazy var c1: () -> () = { println(self) println(self.name) } var c2: () -> () { get { return { println(self) } } } var c3: () -> () { return { println(self) } } override func viewDidLoad() { super.viewDidLoad() c1() c2() c3() } }
Output
<_TtC12TableViewApp19TableViewController: 0x10d54e000>
anil
<_TtC12TableViewApp19TableViewController: 0x10d54e000> <_TtC12TableViewApp19TableViewController: 0x10d54e000>
Update
Assigning closure to a class instance variable results strong reference cycle. You should avoid this. Swift uses Capture list for that
If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures.
So the correct usage of closure could be
@lazy var c1: () -> () = { [unowned self] in println(self) println(self.name) }
Reference: Swift programming guide
Edit
@lazy has been changed to lazy
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With