Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 3: Why symbol _ is added before sender in parameters of action?

My Xcode has been recently updated to Xcode 8 with Swift 3. What I have noticed is that when attaching actions to ViewController functions are generated in this style:

@IBAction func methodName(_ sender: UIButton) {

}

I don't understand what is the purpose of having _ there. Could anyone explain why it is there? In previous Swift 2.2 it was not there.

Another question is that previous project I have done by watching tutorial has migrated to Swift 3, and there was one method which looked like this:

func toggleButtons(toggle: Bool) {
    yesButton.isUserInteractionEnabled = toggle
    noButton.isUserInteractionEnabled = toggle
}

I was calling this method like this: toggleButtons(false) still not passing the argument name. Now migrator has changed it as below but nothing was changed in calling of method later in code.

func toggleButtons(_ toggle: Bool) {
    yesButton.isUserInteractionEnabled = toggle
    noButton.isUserInteractionEnabled = toggle
}

Is it a different situation from the previous case?

like image 496
Marat Avatar asked Sep 18 '16 05:09

Marat


2 Answers

The other answers (one of which has been deleted) covered what the _ means: it eliminates the keyword when you call the method.

However, your question is specifically about “attaching actions to ViewController”.

Methods that have the @IBAction attribute can be connected to controls in your storyboard (or xib). That means the name of the method will be stored, as a string, in the storyboard, and it will be called using the Objective-C message sending system. So the exact name, and how the name is translated to Objective-C, matters very much here.

If you declare the method func methodName(sender: UIButton), then its Objective-C name is methodNameWithSender:.

If you declare the method func methodName(_ sender: UIButton), then its Objective-C name is methodName:.

Both iOS and macOS have something called the “responder chain”, which lets the system search for an object (a “responder”) that can handle an action. You can connect the controls in your storyboard to the First Responder (at the top of the document outline) to have the system do this. Most commonly you do this with menu items in macOS, but there are other uses.

Anyway, there are some standard actions like cut:, copy: and paste:. For example, you would set your Cut menu item's action to send cut: to First Responder. And if you want to implement the cut: method in your view controller, it is critical that its name (when translated to Objective-C) be precisely cut:, and not cutWithSender:. If it's named cut:, the system will find it when searching the responder chain, but if it's named cutWithSender:, the system will not find it and you will wonder why your menu item doesn't work.

Xcode knows this, so it always creates action methods of the form @IBAction func action(_ sender: UIButton), omitting the keyword from the argument, in case you are implementing an action that needs to be found by searching the responder chain.

In Swift 3, every argument to a method has a keyword by default, including the first argument. Back in Swift 2, the first argument did not have a keyword by default, so the _ on the first argument was redundant in Swift 2 (and would generate a compiler warning). That is why Xcode 8 (Swift 3) puts in the _ but Xcode 7 (Swift 2.2) did not.

That is also why your toggleButtons example worked in Xcode 7.

like image 126
rob mayoff Avatar answered Oct 18 '22 20:10

rob mayoff


It means that you do not have to name the parameter when calling the method.

obj.methodName(button)

// no need for
obj.methodName(sender: button)

In earlier Swift versions, that was the special default behaviour for the first parameter in a method call, but in Swift3 that has been unified. All parameters now need names, unless you opt out (with the _).

like image 34
Thilo Avatar answered Oct 18 '22 20:10

Thilo