Attach parameter to button.addTarget action in Swift

I am trying to pass an extra parameter to the buttonClicked action, but I cannot determine what syntax should be in Swift.

button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside) 

Any my buttonClicked method:

 func buttonClicked(sender:UIButton) { println("hello") } 

Any ideas?

Thanks for your help.

+84
button swift uibutton
Jul 17 '14 at 22:35
source share
11 answers

You cannot pass custom parameters to addTarget: One alternative is to set the tag property of the button and do the work based on the tag.

 button.tag = 5 button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside) 

Or for Swift 2.2 and higher:

 button.tag = 5 button.addTarget(self,action:#selector(buttonClicked), forControlEvents:.TouchUpInside) 

Now the logic is based on the tag property

 @objc func buttonClicked(sender:UIButton) { if(sender.tag == 5){ var abc = "argOne" //Do something for tag 5 } print("hello") } 
+146
Jul 17 '14 at 23:08
source share

If you want to send additional parameters to the buttonClicked method, such as indexPath or urlString, you can subclass UIButton:

 class subclassedUIButton: UIButton { var indexPath: Int? var urlString: String? } 

Be sure to change the button class in the identity inspector to subclassedUIButton. You can access the parameters inside the buttonClicked method using sender.indexPath or sender.urlString .

Note. If your button is inside a cell, you can set the value of these additional parameters in the cellForRowAtIndexPath method (where the button is created).

+65
Oct 08 '15 at 2:09
source share

I appreciate everyone who says usage tags, but actually you need to extend the UIButton class and just add an object there.

Tags are a hopeless way. Extend UIButton like this (in Swift 4)

 import UIKit class PassableUIButton: UIButton{ var params: Dictionary<String, Any> override init(frame: CGRect) { self.params = [:] super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { self.params = [:] super.init(coder: aDecoder) } } 

then your call could be Selector(("webButtonTouched:")) (NOTE: A colon ":" in Selector(("webButtonTouched:")) )

 let webButton = PassableUIButton(frame: CGRect(x:310, y:40, width:40, height:40)) webButton.setTitle("Visit",for: .normal) webButton.addTarget(self, action: #selector(YourViewController.webButtonTouched(_:)), for:.touchUpInside) webButton.params["myvalue"] = "bob" 

then finally catch it all here

 @IBAction func webButtonTouched(_ sender: PassableUIButton) { print(sender.params["myvalue"] ?? "") } 

You do this once and use it throughout your project (you can even force the child class to have a common “object” and put whatever you like into the button!). Or use the above example to add an inexhaustible number of key / string parameters to the button. Really useful for including things like URLs, confirmation of message methodology, etc.

On the side, it is important that the SO community realizes this, there is a whole generation of bad practice that is being reduced on the Internet by an alarming number of programmers who do not understand / learn / miss the point of the object extensions concept

+21
Oct. 25 '17 at 13:55 on
source share

For Swift 3.0 you can use the following

 button.addTarget(self, action: #selector(YourViewController.YourMethodName(_:)), for:.touchUpInside) func YourMethodName(_ sender : UIButton) { print(sender.tag) } 
+9
Dec 27 '16 at 12:30
source share

In Swift 3, make the selector like this:

 button.addTarget(self, action: #selector(ViewController.multipleParamSelector(_:secondParams:)), for: .touchUpInside) 

And catch the event as follows:

 func multipleParamSelector(_ sender: AnyObject, secondParams: AnyObject) { } 
+5
Dec 27 '16 at 11:28
source share

Swift 4.0 (here we are again and again)

The action being called should be marked this way because it is the syntax for a quick function to export functions to the object language c.

 @objc func deleteAction(sender: UIButton) { } 

create a working button:

 let deleteButton = UIButton(type: .roundedRect) deleteButton.setTitle("Delete", for: []) deleteButton.addTarget(self, action: #selector( MyController.deleteAction(sender:)), for: .touchUpInside) 
+3
Oct 17 '17 at 11:21 on
source share

Swift 4.2

Result:

 testButton.on(.touchUpInside) { (sender, event) in // You can use any reference initialized before the code block here // You can access self by adding [weak self] before (sender, event) // You can then either make self strong by using a guard statement or use a optional operator (?) print("user did press test button") } 

In the UIButton+Events.swift I created an extension method for UIButton that binds UIControl.Event with a completion handler named EventHandler :

 import UIKit fileprivate var bindedEvents: [UIButton:EventBinder] = [:] fileprivate class EventBinder { let event: UIControl.Event let button: UIButton let handler: UIButton.EventHandler let selector: Selector required init( _ event: UIControl.Event, on button: UIButton, withHandler handler: @escaping UIButton.EventHandler ) { self.event = event self.button = button self.handler = handler self.selector = #selector(performEvent(on:ofType:)) button.addTarget(self, action: self.selector, for: event) } deinit { button.removeTarget(self, action: selector, for: event) if let index = bindedEvents.index(forKey: button) { bindedEvents.remove(at: index) } } } private extension EventBinder { @objc func performEvent(on sender: UIButton, ofType event: UIControl.Event) { handler(sender, event) } } extension UIButton { typealias EventHandler = (UIButton, UIControl.Event) -> Void func on(_ event: UIControl.Event, handler: @escaping EventHandler) { bindedEvents[self] = EventBinder(event, on: self, withHandler: handler) } } 

The reason I used a custom class to bind an event is to be able to remove the link later when the button is uninitialized. This will prevent a possible memory leak. This was not possible in UIButton extending it because I was not allowed to implement a property or method deinit .

+3
Dec 14 '18 at 11:42
source share

If you have a button loop like me, you can try something like this

 var buttonTags:[Int:String]? // can be [Int:Any] let myArray = [0:"a",1:"b"] for (index,value) in myArray { let button = // Create a button buttonTags?[index] = myArray[index] button.tag = index button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchDown) } @objc func buttonAction(_ sender:UIButton) { let myString = buttonTags[sender.tag] } 
+2
Jul 21 '17 at 9:41
source share

For Swift 2.X and higher

 button.addTarget(self,action:#selector(YourControllerName.buttonClicked(_:)), forControlEvents:.TouchUpInside) 
0
Sep 13 '16 at 13:27
source share

Swift 3.0 Code

 self.timer = Timer.scheduledTimer(timeInterval: timeInterval, target: self, selector:#selector(fetchAutocompletePlaces(timer:)), userInfo:[textView.text], repeats: true) func fetchAutocompletePlaces(timer : Timer) { let keyword = timer.userInfo } 

You can send the value to userinfo and use it as a parameter in a function.

0
Mar 23 '17 at 11:14
source share

Swift 5.0 Code

I use theButton.tag, but if I have many options, this will be a very long switch case.

 theButton.addTarget(self, action: #selector(theFunc), for: .touchUpInside) theButton.frame.name = "myParameter" 

,

 @objc func theFunc(sender:UIButton){ print(sender.frame.name) } 
0
Apr 17 '19 at 23:55
source share



All Articles