Anthony Dito
Anthony Dito

Reputation: 3670

What the "self" refers to in closure - Swift

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

Answers (3)

matt
matt

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

Andrea
Andrea

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

user3441734
user3441734

Reputation: 17534

Is the instance of MyClass captured?

Yes.

Upvotes: 1

Related Questions