How to use one IBAction for multiple buttons in Swift?

36,756

Solution 1

In Interface Builder, select the Attributes Inspector and set the Tag for each button with a unique number, then you can do something like this:

@IBAction changeLanguage(sender: AnyObject) {
    guard let button = sender as? UIButton else {
        return
    }

    switch button.tag {
    case 1:
        // Change to English
    case 2:
        // Change to Spanish
    case 3:
        // Change to French, etc
    default:
        print("Unknown language")
        return
    }
}

To connect the action to multiple buttons: in Interface Builder, right-click ViewController in the view hierarchy, then left-click to drag the action connection to each button.

Solution 2

Yes, a switch statement is the way to go here. For a UIButton, you link it to a selector that is called when the user interacts with the button, generally the TouchUpInside event. The addTarget method, and valid selector signatures (apple.com) Of these, you want to use a method in the format @IBAction func doSomething(sender: UIButton) or @IBAction func doSomething(sender: UIButton, forEvent event: UIEvent), so that a reference to the button that triggered the event is passed to the selector.

In your ViewController code, you'll have references to your UIButtons (possibly in a storyboard, or created manually.) Let's say you have

@IBOutlet weak var frenchButton: UIButton!
@IBOutlet weak var spanishButton: UIButton!
@IBOutlet weak var englishButton: UIButton!

You would connect all of them to the same method, and branch the logic based on which one was the sender. e.g.:

@IBAction func changeLanguage(sender: UIButton) {
    switch sender {
    case frenchButton:
        // Change Language to French
        print ("C'est si bon")
    case spanishButton:
        // or Spanish
        print ("Muy Bueno")
    case englishButton:
        // or English
        print ("It's pretty cool")
    default:
        break

    }

}

Note: Case statements in Swift must be exhaustive, so you have to include a default case, even though it should never be called.

Solution 3

Do not set tag if you have reference to the button.

You can just compare the reference instead of tags. This way, you won't introduce a new bug, because unlike a tag that you type yourself, reference is created by compiler automatically.

@IBOutlet weak var firstButton: UIButton!
@IBOutlet weak var secondButton: UIButton!
@IBOutlet weak var thirdButton: UIButton!

@IBAction changeLanguage(sender: UIButton) {
    if sender == firstButton {

    } else if sender == secondButton {

    } else if sender == thirdButton {

    }
}
Share:
36,756
SwiftyJD
Author by

SwiftyJD

Updated on June 01, 2020

Comments

  • SwiftyJD
    SwiftyJD almost 4 years

    I have multiple buttons each one with the ability to switch the language of the app. Instead of having to create multiple IBActions for each button is there a way to have them all connected to one IBAction and change the language based on the button pressed? I'm thinking a switch statement would be good to use in this situation but not exactly sure how to set it up.

  • SwiftyJD
    SwiftyJD almost 8 years
    How can you connect each button to the action in storyboard? It won't allow me to click the button and drag to the IBAction.
  • Code Different
    Code Different almost 8 years
    in Interface Builder, right-click ViewController in the view hierarchy, then left-click to drag the action connection to each button
  • toddg
    toddg over 7 years
    @CodeDifferent I would recommend editing your post to include your comment about connecting multiple buttons in IB. It helped the OP and it is why I stumbled on this question
  • Antek
    Antek about 6 years
    @CodeDifferent dragging appriopriate actions from many buttons to one action doesn't seem to work for me (XCode 9.3). What may I be doing wrong?