Reputation: 3670
I am having a hard time understanding what is truly happening in a closure in Swift
and was hoping that someone could help me understand.
class MyClass {
func printWhatever(words: String) {
print(words)
}
func doWhatever() {
dispatch_async(...) {
//why self
self.printWhatever("Hello")
}
}
}
On the line self.printWhatever("Hello")
, why do I have to use self
? xCode
always just tells me that I have to, but I am not sure why. So, my question is what exactly is stored in the closure. I know a closure captures the surrounding context. But how much? Is the instance of MyClass
captured?
Upvotes: 1
Views: 793
Reputation: 535086
It's a matter of clarity. Any time you use a method or property name without an explicit recipient, it is implicitly being sent to self
. But in an anonymous function you must make this fact explicit. If you were to say
printWhatever("Hello")
...you might not realize that you are implicitly capturing self
. So you might not realize that, if this anonymous function were itself to be stored somewhere in self
, you can wind up with a dreaded retain cycle. Therefore, the compiler forces you to say self
explicitly, so that you are aware of the implications of your own actions.
The proof of this is that there are circumstances where you do not have to say self
in an anonymous function. Consider this:
func printWhatever(words: String) {
print(words)
}
func doThis(f:()->()) {
f()
}
func doWhatever() {
doThis {
self.printWhatever("Hello") // self is required
}
}
In the above, you must say self
, because the compiler has no guarantee that a retain cycle might not happen. But now watch what happens if we add the @noescape
attribute:
func printWhatever(words: String) {
print(words)
}
func doThis(@noescape f:()->()) { // *
f()
}
func doWhatever() {
doThis {
printWhatever("Hello") // ok!
}
}
The @noescape
attribute guarantees that the passed function will be executed immediately and not stored. Thus self
is no longer required, because no retain cycle can take place.
Personally, I always say self
wherever I am allowed to, as a matter of style. And I suggest you do the same.
NOTE: There was a language-change proposal that was rejected, and one of the grounds for rejection was the very one that I give:
The requirement to use
self.
within potentially-escaping closures is a useful indicator of the potential for retain cycles
Upvotes: 4
Reputation: 26385
self
is required to capture the instance of the object you want to send the message. Without it the compiler doesn't know who to send the message.
Pay attention that sometimes having self
into a clojure can lead to reference cycle, basically the captured object will never be released, in htis case you should create a capture list inside the clojure and specify a different memory manage such as unowned
or weak
Upvotes: 1