Get button pressed id on Swift via sender - swift

So I have a storyboard with 3 buttons I want to just create 1 action for all those 3 buttons and decide what to do based on their label/id...
Is there a way to get some kind of identifier for each button?
By the way they are images, so they don't have a title.
#IBAction func mainButton(sender: UIButton) {
println(sender)
}

You can set a tag in the storyboard for each of the buttons. Then you can identify them this way:
#IBAction func mainButton(sender: UIButton) {
println(sender.tag)
}
EDIT: For more readability you can define an enum with values that correspond to the selected tag. So if you set tags like 0, 1, 2 for your buttons, above your class declaration you can do something like this:
enum SelectedButtonTag: Int {
case First
case Second
case Third
}
And then instead of handling hardcoded values you will have:
#IBAction func mainButton(sender: UIButton) {
switch sender.tag {
case SelectedButtonTag.First.rawValue:
println("do something when first button is tapped")
case SelectedButtonTag.Second.rawValue:
println("do something when second button is tapped")
case SelectedButtonTag.Third.rawValue:
println("do something when third button is tapped")
default:
println("default")
}
}

If you want to create 3 buttons with single method then you can do this by following code...Try this
Swift 3
Example :-
override func viewDidLoad()
{
super.viewDidLoad()
Button1.tag=1
Button1.addTarget(self,action:#selector(buttonClicked),
for:.touchUpInside)
Button2.tag=2
Button2.addTarget(self,action:#selector(buttonClicked),
for:.touchUpInside)
Button3.tag=3
Button3.addTarget(self,action:#selector(buttonClicked),
for:.touchUpInside)
}
func buttonClicked(sender:UIButton)
{
switch sender.tag
{
case 1: print("1") //when Button1 is clicked...
break
case 2: print("2") //when Button2 is clicked...
break
case 3: print("3") //when Button3 is clicked...
break
default: print("Other...")
}
}

You can create an outlet for your buttons and then implement:
#IBAction func mainButton(sender: UIButton) {
switch sender {
case yourbuttonname:
// do something
case anotherbuttonname:
// do something else
default: println(sender)
}
}

Swift 4 - 5.1
#IBAction func buttonPressed(_ sender: UIButton) {
if sender.tag == 1 {
print("Button 1 is pressed")
}
}

You have to set tag value to what you need and access it with
sender.tag

Assuming you gave them all proper names as #IBOutlets:
#IBOutlet var weak buttonOne: UIButton!
#IBOutlet var weak buttonTwo: UIButton!
#IBOutlet var weak buttonThree: UIButton!
You can use the following to determine which is which
#IBAction func didPressButton(sender: AnyObject){
// no harm in doing some sort of checking on the sender
if(sender.isKindOfClass(UIButton)){
switch(sender){
case buttonOne:
//buttonOne action
break
case buttonTwo:
//buttonTwo action
break
case buttonThree:
//buttonThree action
break
default:
break
}
}

Swift 3 Code:
In xcode Please set tag for each button first to work following code.
#IBAction func threeButtonsAction(_ sender: UIButton) {
switch sender.tag {
case 1:
print("do something when first button is tapped")
break
case 2:
print("do something when second button is tapped")
break
case 3:
print("do something when third button is tapped")
break
default:
break
}
}

You can do like this, just you have to give tag to all the buttons and do like this:
#IBAction func mainButton(sender: AnyObject)
{
switch sender.tag {
case 1:
println("do something when first button is tapped")
case 2:
println("do something when second button is tapped")
case 3:
println("do something when third button is tapped")
default:
println("default")
}
}

Use the outlets instead, tags clutter the code and make the readability way worse. Think about the poor developer that reads the code next and sees if sender.tag = 381 { // do some magic }, it just won't make any sense.
My example:
class PhoneNumberCell: UITableViewCell {
#IBOutlet weak var callButton: UIButton!
#IBOutlet weak var messageButton: UIButton!
#IBAction func didSelectAction(_ sender: UIButton) {
if sender == callButton {
debugPrint("Call person")
} else if sender == messageButton {
debugPrint("Message person")
}
}
[...]
}
You could also do this in a nice switch as well, which would make it even better.
Tested on Swift 5.1

Swift 4
add tag on button
let button = UIButton()
button.tag = 10
click event
#IBAction func mainButton(sender: UIButton) {
switch sender.tag {
case 10:
print("10")
case 11:
print("11")
default:
print("yes")
}
}

In this case you can use NSObject extension Accessibility Element UIAccessibility.
I have used accessibilityLabel and accessibilityIdentifier both are success in call and condition checking.
First
You can set a Accessibility Label or Identifier in the storyboard for each of the buttons in Identity inspector. Accessibility should be enabled.
To check/Identify button by
#IBAction func selectionPicker(_ sender: UIButton){
if sender.accessibilityLabel == "childType"{ //Check by accessibilityLabel
print("Child Type")
}
if sender.accessibilityIdentifier == "roomType"{ //Check by accessibilityIdentifier
print("Room Type")
}
performSegue(withIdentifier: "selectionViewSegue", sender:sender)
}
On Swift 3.2 and 4.0 with Xcode 9.0

Given the case you labeled your buttons "1", "2", "3":
#IBAction func mainButton(sender: UIButton) {
switch sender.titleLabel?.text {
case "1":
print("do something when first button is tapped")
case "2":
print("do something when second button is tapped")
case "3":
print("do something when third button is tapped")
default:
() // empty statement or "do nothing"
}
}

Swift 5.5
I have utility methods in other classes that do not have an instance of my ViewController, so I don't compare the sent objects to what is defined in the ViewController's IBOutlets.
I don't use tags if I can use a plain language identifier on my UI objects. I'd rather have plain language identifiers than numbers to identify my objects because it is easier for me. Just another way of doing it.
If I need to use a utility method, I set it up with a sender parameter so I can send the button and then figure out which button was clicked based on the assigned identity of the button within Storyboard.
For example:
class Utility {
func doSomething(sender: Any?) {
guard let button = sender as? NSButton else {
print("Unable to set button from sender.")
return
}
guard case buttonID = button.identifier?.rawValue else {
print("Unable to get button identifier.")
return
}
switch buttonID {
case: "firstButton":
_ = buttonID // Perform firstButton action
case: "secondButton":
_ = buttonID // Perform secondButton action
case: "thirdButton":
_ = buttonID // Perform thirdButton action
default:
// shouldn't get here - error?
}
}
}
In my ViewController I have the following buttons set up as IBOutlets and their identity is the same in Storyboard.
#IBOutlet weak var firstButton: NSButton?
#IBOutlet weak var secondButton: NSButton?
#IBOutlet weak var thirdButton: NSButton?
Then I have my IBActions:
#IBAction func firstButtonClicked(sender: Any?) {
utility.doSomething(sender: sender)
}
#IBAction func secondButtonClicked(sender: Any?) {
utility.doSomething(sender: sender)
}
#IBAction func thirdButtonClicked(sender: Any?) {
utility.doSomething(sender: sender)
}

In my case what i did, just like the answers above i used the tag to identify the specific button, what i added is that i added a UIButton extension that adds an id so that i can set a string id
i had three buttons with tags 0, 1 and 2
Then created the extension
extension UIButton {
var id: String {
let tag = self.tag
switch tag {
case 0:
return "breakfast"
case 1:
return "lunch"
case 2:
return "dinner"
default:
return "None"
}
}
}
When accessing a button in an IBAction i would just call:
sender.id

Select your first button and give it tag 0, and select second button and give it tag 1 and so on, in action check the tag bit and perform you functionalities on the basis of tag bit.:

switch sender as! NSObject {
case self.buttoneOne:
println("do something when first button is tapped")
case self.buttoneTwo:
println("do something when second button is tapped")
default:
println("default")
}

Related

Swift - How to get the sender tag for an array of buttons using UILongPressGestureRecognizer?

I have buttons in the storyboard that I put into a Referencing Outlet Collection. I'm using UITapGestureRecognizer and UILongPressGestureRecognizer for all of these buttons, but how can I print exactly which button gets tapped? Bellow is what I tried but doesn't work. I get an error that says "Value of type 'UILongPressGestureRecognizer' has no member 'tag'." I'm trying to build the button grid for the Minesweeper game. Thank you for your help.
class ViewController: UIViewController {
#IBOutlet var testButtons: [UIButton]! // There are 100 buttons in this array
override func viewDidLoad() {
super.viewDidLoad()
let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
testButtonPressed.minimumPressDuration = 0.5
// These indexes are just to test how to recognize which button gets pressed
testButtons[0].addGestureRecognizer(testButtonPressed)
testButtons[1].addGestureRecognizer(testButtonPressed)
}
#objc func testPressed(_ sender: UILongPressGestureRecognizer) {
print("Test button was pressed")
print(sender.tag) // THIS DOESN'T WORK, BUT CONCEPTUALLY THIS IS WHAT I WANT TO DO
}
This error occurs because UILongPressGestureRecognizer object has no tag property
You can access sender's button in a way like that:
#objc func testPressed(_ sender: UILongPressGestureRecognizer) {
guard let button = sender.view as? UIButton else { return }
print(button.tag)
}
I think that the best solution to handle button's actions is to add #IBAction
(you can add it like #IBOutlet with a minor change - set Action connection type)
And then in #IBAction block you cann access all button properties (like tag and others)
instead of using gesture I think it would be better to use #IBAction and connect the buttons With it here is a small example
UILongPressGestureRecognizer which is a subclass of UIGestureRecognizer, can be used only once per button or view. Because UILongPressGestureRecognizer has only a single view property. In your code, it will always be testButtons[1] calling the testPressed action. So you have to first modify the viewDidLoad code like this :-
for button in testButtons {
let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
testButtonPressed.minimumPressDuration = 0.5
button.addGestureRecognizer(testButtonPressed)
button.addGestureRecognizer(testButtonPressed)
}
Then you can access the button from testPressed like this (I hope you've already set the tag in the storyboard) :-
#objc func testPressed(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
if let button = sender.view as? UIButton {
print(button.tag)
}
}
}
You need to set tags before pressing!
On the viewDidLoad() method you must add something like:
testButtons.enumerated().forEach {
let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
testButtonPressed.minimumPressDuration = 0.5
$0.element.addGestureRecognizer(testButtonPressed)
$0.element.tag = $0.offset
}
And when the long press is receiving you need to get a tag from view not from the sender!
print(sender.view?.tag)
Since a gesture recognizer should only be associated with a single view, and doesn't directly support using an identity tag to match it with buttons. When creating an array of buttons for a keyboard, with a single gesture response function, I found it easier to use the gesture recognizer "name" property to identify the associated button.
var allNames: [String] = []
// MARK: Long Press Gesture
func addButtonGestureRecognizer(button: UIButton, name: String) {
let longPrssRcngr = UILongPressGestureRecognizer.init(target: self, action: #selector(longPressOfButton(gestureRecognizer:)))
longPrssRcngr.minimumPressDuration = 0.5
longPrssRcngr.numberOfTouchesRequired = 1
longPrssRcngr.allowableMovement = 10.0
longPrssRcngr.name = name
allNames.append(name)
button.addGestureRecognizer(longPrssRcngr)
}
// MARK: Long Key Press
#objc func longPressOfButton(gestureRecognizer: UILongPressGestureRecognizer) {
print("\nLong Press Button => \(String(describing: gestureRecognizer.name)) : State = \(gestureRecognizer.state)\n")
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
if let keyName = gestureRecognizer.name {
if allNames.contains(keyName) {
insertKeyText(key: keyName)
} else {
print("No action available for key")
}
}
}
}
To implement, call the addButtonGestureRecognizer function after creating the button, and provide a name for the button (I used the button text) e.g.
addButtonGestureRecognizer(button: keyButton, name: buttonText)
The button name is stored in the "allNames" string array so that it can be matched later in "longPressOfButton".
When the button name is matched in the "longPressOfButton" response function, it passes it to "addKeyFunction" where it is processed.

Swift 4 - Creating a common function for multiple buttons

I'm wondering if there is a more efficient way to code an action that is the same with the exception of which button has been pressed and which item in a struct it relates to. Basically, I have a struct of 10 variables all of which are a boolean type and I have 10 buttons. When the user presses the button, I want to check whether it has already been pressed (using the struct) and then change the background of the button depending on the state and reverse the state. I've copied my current code for one of the buttons but thought I should be able to avoid doing this 10 times!
#IBAction func architectureButtonPressed(_ sender: Any) {
if myInterests.architecture {
myInterests.architecture = false
architectureButton.setBackgroundImage(imageUncheckedNarrow, for: .normal)
} else {
myInterests.architecture = true
architectureButton.setBackgroundImage(imageCheckedNarrow, for: .normal)
}
}
Well one simple way is to have each UIButton point to the same architectureButtonPressed IBAction method. Since the button that's pressed is passed into the method (sender) you can consult it's tag property to know the index of which field in your struct should be updated. (And then you might want to change your struct to just store an array of 10 bools, but up to you).
Then for each UIButton, whether programmatically in storyboard or nib, you'd assign the appropriate index value to the button's tag field.
Create yours IBOutlet for each button.
Create a array and store all buttons like : var arrayButtons : [UIButton] = []
arrayButtons.append[button1]
arrayButtons.append[button2]
...
Create a array of booleans to store true/false: var arrayBools : [Bool] = [] and initialize if some value.
Note that the indexes of the arrayButtons and arrayBools must be same related.
Create selector function to listen touch buttons.
button.addTarget(self, action: #selector(my_func), for: .touchUpInside)
#objc func my_func(_ sender : UIButton) {
for i in 0...arrayButtons.size-1 {
if arrayButtons[i] == sender {
if arrayBooleans[i] {
arrayBooleans[i] = false
arrayButtons[i].setImage()
} else {
arrayBooleans[i] = true
arrayButtons[i].setImage()
}
}
}
}
My suggestion is to manage the images in Interface Builder via State Config (Default/Selected)
Then assign an unique tag starting from 100 to each button and set the isSelected value in the IBAction to the corresponding struct member in a switch statement:
#IBAction func buttonPressed(_ sender: UIButton) {
switch sender.tag {
case 100: myInterests.architecture = sender.isSelected
case 101: myInterests.art = sender.isSelected
...
default: break
}
}
Alternatively use Swift's native KVC with WriteableKeypath
let keypaths : [WritableKeyPath<Interests,Bool>] = [\.architecture, \.art, \.fashion, \.history, \.localCulture, \.music, \.nature, \.shopping, \.sport, \.anything]
#IBAction func buttonPressed(_ sender: UIButton) {
let index = sender.tag - 100
let keypath = keypaths[index]
myInterests[keyPath: keypath] = sender.isSelected
}

How can I connect two segment controls to each other?

I'm trying to disable the bottom segment control if the user clicks Diesel. The problem is I can't connect two IBActions to each other. Such as:
#IBAction func didSelect(_ control: UISegmentedControl) {
switch control.selectedSegmentIndex
{
case 0:
isPetrol = true
isDiesel = false
case 1:
isPetrol = false
isDiesel = true
default:
print ("break")
}
}
#IBACtion func didSecondSelect (_ control: UISegmentedControl) {
//something here that when case1 is clicked disables it
}
}
How can I disable it if the top case 1 is clicked?
You are mixing up IBActions and IBOutlets.
You should create an IBOutlet that points to the second segmented control and change that from the first one's code.
#IBOutlet weak var secondSegmentedControl: UISegmentedControl!
#IBAction func didSelect(_ control: UISegmentedControl) {
[...]
secondSegmentedControl.isEnabled = control.selectedSegmentIndex == 0
}
For more information about working with IBOutlets, check out this question.

How can I check the currentTitle of a UIButton in a switch?

I have a UIButton which changes the title in different situations.
If you press the button the currentTitle should be checked by a Swift Switch (and certain Code executed).
The following isn't working:
#IBAction func button(_ sender: UIButton) {
switch sender.currentTitle {
case "":
//Code
case "OK":
//Code
default:
}
}
Xcode just shows "Expected Pattern" (1st cause) and "Expected Expression" (2nd case)
per the documentation, UIButton.currentTitle is of type String?. (optional type String)
Your switch statement is comparing an optional type to a non-optional type which is the reason you see errors.
Suggest first unwrapping the value before checking it's value with a switch like:
guard let title = sender.currentTitle() else { return }
switch title {
...
}
Every case in a switch statement must have a line of code. If you don't want to do anything you can use break:
#IBAction func button(_ sender: UIButton) {
switch sender.currentTitle {
case "":
//Code
case "OK":
//Code
default:
break
}
}
I solved the problem accidentally by adding questions marks
#IBAction func button(_ sender: UIButton) {
switch sender.currentTitle {
case ""?:
//Code
case "OK"?:
//Code
default:
break
}
}
I don't know why but it works nevertheless thanks for helping me.

Xcode v7.2 - New Radio Buttons: How to find selected

I am attempting to detect which Radio Button is currently selected using Xcode 7's new Radio Button template (NSButton).
I have created a simple action that will print to log the title of the sender when a radio button is selected. This does work:
#IBAction func radioButtonClicked(sender: AnyObject)
{
print(sender.selectedCell()!.title);
}
But what I am really looking for is the ability to know which radio button is selected elsewhere in my codes (specifically on an IBAction for a button click). I have tried:
#IBAction func uploadButtonPressed(sender: AnyObject)
{
print (radioButton.selectedCell()!.title);
}
This does compile and execute, the problem is it always gives me the title of the first radio button not the one that is actually selected.
Any ideas?
The "closest" I can get (which is not very clean, but works "kinda") is to see if radioButton.cell?state = 1. This tells me that the first radio button is selected. But this is a very poor way to code this and only allows for 2 radio button options.
if (radioButton.cell?.state == 1)
{
print ("Radio 1 Selected");
}
else
{
print ("Radio 2 Selected");
}
Use the identifier or tag property in Interface Builder to distinguish between radio buttons like:
#IBAction func selectOption(sender: AnyObject) {
let id:String = sender.identifier!!
case "first identifier":
// do some stuff
// ...
default:
// do default stuff
}
Another option would be a switch-case statement and defining outlets for each radio button like:
#IBOutlet weak var firstOption: NSButton!
#IBOutlet weak var secondOption: NSButton!
#IBOutlet weak var thirdOption: NSButton!
#IBAction func selectOption(sender: AnyObject) {
switch sender as! NSButton {
case firstOption:
print("firstOption")
case secondOption:
print("secondOption")
case thirdOption:
print("thirdOption")
default:
print("won't be called when exhaustive but must always be implemented")
}
}
I ended up finding a method for this.
First I setup a variable to store which item was checked (and pre-set the value to the value I want for the first radio button)
var databaseUploadMethod = "trickle-add";
Then I compare to see the title value of the selected item:
#IBAction func radioButtonClicked(sender: AnyObject)
{
if ((sender.selectedCell()!.title) == "Trickle Add")
{
databaseUploadMethod = "trickle-add";
}
else if ((sender.selectedCell()!.title) == "Bulk Add All Now")
{
databaseUploadMethod = "bulk-add";
}
}
For reference: I have two radio buttons, the first has a title of "Trickle Add" and the second is "Bulk Add All Now". Those are the values I am comparing in my if statement.