How to send additional parameter in addtarget function? - ios

please anyone tell me, How to send additional parameter in addtarget function in swift 2.2?
Example:
button.addTarget(self, action: #selector(classname.myFunc(_:)), forControlEvents: UIControlEvents.TouchUpInside))
func myFunc(sender:UIButton){
print(“i am here“)
}
to
func myFunc(sender:UIButton,parameter:String){
print(“i am here“)
}

You can create a subclass of UIButton, add one property named parameter which you want to pass as an extra parameter.
In addTarget(), you can only choose passing the caller or not. In this case, the caller is a UIButton.
So use the subclass and call addTarget(), then you can get the string which you want send:
func myFunc(sender: customUIButton) {
// do something with sender.parameter
}
Hope it can help you.

In Swift 2.2 you can do something like this.
myUISlider.addTarget(self, action:#selector(self.onSliderValChanged(_:withEvent:)), forControlEvents: .ValueChanged)
func onSliderValChanged(slider: UISlider, withEvent event: UIEvent?) {
}

I use sender properties to send some parameters with it like
button.accessibilityHint = "param 1"
button.accessibilityValue = "param 2"
button.tag = 0
button.addTarget(self, action: #selector(buttonPressed(_:)), forControlEvents: UIControlEvents.TouchUpInside))
func myFunc(sender:UIButton){
print(sender.accessibilityHint) // param1
print(sender.accessibilityValue) // param2
print(sender.tag) // 0
}

It's not possible. You have to use a workaround.
button.addTarget(self, action: #selector(classname.myFunc(_:)), forControlEvents: UIControlEvents.TouchUpInside))
func myFunc(sender:UIButton){
self.myFunc2(sender, parameter: "My parameter")
}
func myFunc2(sender:UIButton,parameter:String){
}

Swift 5.0 code
theButton.addTarget(self, action: #selector(theFunc), for: .touchUpInside)
theButton.frame.name = "myParameter"
.
#objc func theFunc(sender:UIButton){
print(sender.frame.name)
}

Related

Pass parameters to button action in swift

When setting the action with the "addTarget" method on a button in Swift, is there a way for me to pass a parameter to the function I want to trigger?
Say I had a simple scenario like this:
let button = UIButton()
button.addTarget(self, action: #selector(didPressButton), for: .touchUpInside)
#objc func didPressButton() {
// do something
}
Obviously the above code works fine, but say I wanted the 'didPressButton' function to take in a parameter:
#objc func didPressButton(myParam: String) {
// do something with myParam
}
Is there a way I can pass a parameter into the function in the 'addTarget' method?
Something like this:
let button = UIButton()
button.addTarget(self, action: #selector(didPressButton(myParam: "Test")), for: .touchUpInside)
#objc func didPressButton(myParam: String) {
// do something with myParam
}
I'm coming from a JavaScript background and in JavaScript it's pretty simple to achieve this behavior by simply passing an anonymous function that would then call the 'didPressButton' function. However, I can't quite figure how to achieve this with swift. Can a similar technique be used by using a closure? Or does the '#selector' keyword prevent me from doing something like that?
Thank you to anyone who can help!
The short answer is no.
The target selector mechanism only sends the target in the parameters. If the string was a part of a subclass of UIbutton then you could grab it from there.
class SomeButton: UIButton {
var someString: String
}
#objc func didPressButton(_ button: SomeButton) {
// use button.someString
}
It is not possible to do that in iOS. You can get the View in the selector in your case it is a button.
button.addTarget(self, action: #selector(buttonClick(_:)), for: .touchUpInside)
#objc func buttonClick(_ view: UIButton) {
switch view.titleLabel?.text {
case "Button":
break
default:
break
}
}

UIButton add target without sender

I have a UIDatePicker. After a date is selected I call this method
func goToNextScreen(selectedDate: Date) {
//...
}
Now I have added a UIButton. In that button action I want to call the same method goToNextScreen without any date value. Date value is optional in next screen. I tried the following code
btn.addTarget(self, action: #selector(goToNextScreen), for: .touchUpInside)//goToNextScreen(_:)
#objc func goToNextScreen(selectedDate: Date? = nil) {
//...
}
When the button is tapped the app crashes.
How to solve this without adding another method? If it is not possible why my approach doesn't work
What is happening here is, the button's internal logic is trying to pass the sender, which is a UIButton into your method's Date parameter. However, the sender parameter won't get passed if your method don't have any arguments.
Optional parameters don't really work in this situation. What you can do however, is to create another parameterless overload for goToNextScreen:
#objc func goToNextScreen() {
goToNextScreen(selectedDate: nil)
}
And change
btn.addTarget(self, action: #selector(goToNextScreen), for: .touchUpInside)
to
btn.addTarget(self, action: #selector(goToNextScreen as () -> Void), for: .touchUpInside)
so that it different between the two overloads.
Note that the reason why just writing #selector(goToNextScreen) is ambiguous is because you have two methods named goToNextScreen, and Swift needs to resolve to one of them. But it can't with just the name. Here is a similar situation:
class Foo {
#objc func f() {}
func f(x: Int) {}
let selector: Selector = #selector(f) // ambiguous use of f
}
Edit: You can't really do this without creating another method. Selectors are inflexible things.
It's not possible in this case re-use the same method. You should create a new one without parameters or whose parameters are UIButton (or a more generic type, often is Any) and the UIEvent.
Here's the explanation of the Target-Action mechanism: UIControl.
I thought you've to try this
var selectedDate = Date()
btn.addTarget(self, action: #selector(goToNextScreen), for: .touchUpInside)//goToNextScreen(_:)
#objc func goToNextScreen(_ sender: UIButton)
{
selectedDate ?? self.datePickerDate : Date()
}
Using Any as sender type and casting to Date works
//add button Target
btn.addTarget(self, action: #selector(goToNextScreen(_:)), for: .touchUpInside)
//Call with date value
goToNextScreen(Date())
#objc func goToNextScreen(_ selectedDate: Any) {
nextVC.date = selectedDate as? Date
//...
}
sender paramter of UIButton is casted to Date which is reason of crash , it should be a UIButton
btn.addTarget(self, action: #selector(btnClicked), for: .touchUpInside)//goToNextScreen(_:)
#objc func btnClicked(_ sender:UIButton) {
// call next here
goToNextScreen()
}
func goToNextScreen(_ selectedDate: Date? = nil) {
if let date = selectedDate { }
}

How to use addTarget method in swift 3. Convert 2.3 to 3.0 [duplicate]

here is my button object
let loginRegisterButton:UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(r: 50 , g: 80, b: 130)
button.setTitle("Register", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action:#selector(handleRegister), for: .touchUpInside)
return button
}()
and here is my function
func handleRegister(){
FIRAuth.auth()?.createUser(withEmail: email, password: password,completion: { (user, error) in
if error != nil
{ print("Error Occured")}
else
{print("Successfully Authenticated")}
})
}
I'm getting compile error, if addTarget removed it compiles successfully
Yes, don't add "()" if there is no param
button.addTarget(self, action:#selector(handleRegister), for: .touchUpInside).
and if you want to get the sender
button.addTarget(self, action:#selector(handleRegister(_:)), for: .touchUpInside).
func handleRegister(sender: UIButton){
//...
}
Edit:
button.addTarget(self, action:#selector(handleRegister(_:)), for: .touchUpInside)
no longer works, you need to replace _ in the selector with a variable name you used in the function header, in this case it would be sender, so the working code becomes:
button.addTarget(self, action:#selector(handleRegister(sender:)), for: .touchUpInside)
Try this with Swift 4
buttonSection.addTarget(self, action: #selector(actionWithParam(_:)), for: .touchUpInside)
#objc func actionWithParam(sender: UIButton){
//...
}
buttonSection.addTarget(self, action: #selector(actionWithoutParam), for: .touchUpInside)
#objc func actionWithoutParam(){
//...
}
Try this
button.addTarget(self, action:#selector(handleRegister()), for: .touchUpInside).
Just add parenthesis with name of method.
Also you can refer link : Value of type 'CustomButton' has no member 'touchDown'
let button: UIButton = UIButton()
button.setImage(UIImage(named:"imagename"), for: .normal)
button.addTarget(self, action:#selector(YourClassName.backAction(_sender:)), for: .touchUpInside)
button.frame = CGRect.init(x: 5, y: 100, width: 45, height: 45)
view.addSubview(button)
#objc public func backAction(_sender: UIButton) {
}
Try with swift 3
cell.TaxToolTips.tag = indexPath.row
cell.TaxToolTips.addTarget(self, action: #selector(InheritanceTaxViewController.displayToolTipDetails(_:)), for:.touchUpInside)
#objc func displayToolTipDetails(_ sender : UIButton) {
print(sender.tag)
let tooltipString = TaxToolTipsArray[sender.tag]
self.displayMyAlertMessage(userMessage: tooltipString, status: 202)
}
In swift 3 use this -
object?.addTarget(objectWhichHasMethod, action: #selector(classWhichHasMethod.yourMethod), for: someUIControlEvents)
For example(from my code) -
self.datePicker?.addTarget(self, action:#selector(InfoTableViewCell.datePickerValueChanged), for: .valueChanged)
Just give a : after method name if you want the sender as parameter.
Try this with Swift 3
button.addTarget(self, action:#selector(ClassName.handleRegister(sender:)), for: .touchUpInside)
Good luck!
The poster's second comment from September 21st is spot on. For those who may be coming to this thread later with the same problem as the poster, here is a brief explanation. The other answers are good to keep in mind, but do not address the common issue encountered by this code.
In Swift, declarations made with the let keyword are constants. Of course if you were going to add items to an array, the array can't be declared as a constant, but a segmented control should be fine, right?! Not if you reference the completed segmented control in its declaration.
Referencing the object (in this case a UISegmentedControl, but this also happens with UIButton) in its declaration when you say .addTarget and let the target be self, things crash. Why? Because self is in the midst of being defined. But we do want to define behaviour as part of the object... Declare it lazily as a variable with var. The lazy fools the compiler into thinking that self is well defined - it silences your compiler from caring at the time of declaration. Lazily declared variables don't get set until they are first called. So in this situation, lazy lets you use the notion of self without issue while you set up the object, and then when your object gets a .touchUpInside or .valueChanged or whatever your 3rd argument is in your .addTarget(), THEN it calls on the notion of self, which at that point is fully established and totally prepared to be a valid target. So it lets you be lazy in declaring your variable. In cases like these, I think they could give us a keyword like necessary, but it is generally seen as a lazy, sloppy practice and you don't want to use it all over your code, though it may have its place in this sort of situation. What it
There is no lazy let in Swift (no lazy for constants).
Here is the Apple documentation on lazy.
Here is the Apple on variables and constants. There is a little more in their Language Reference under Declarations.
Instead of
let loginRegisterButton:UIButton = {
//... }()
Try:
lazy var loginRegisterButton:UIButton = {
//... }()
That should fix the compile error!!!
the Demo from Apple document. https://developer.apple.com/documentation/swift/using_objective-c_runtime_features_in_swift
import UIKit
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// without parameter style
let action = #selector(MyViewController.tappedButton)
// with parameter style
// #selector(MyViewController.tappedButton(_:))
myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
}
#objc func tappedButton(_ sender: UIButton?) {
print("tapped button")
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}

How to use addTarget method in swift 3

here is my button object
let loginRegisterButton:UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(r: 50 , g: 80, b: 130)
button.setTitle("Register", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action:#selector(handleRegister), for: .touchUpInside)
return button
}()
and here is my function
func handleRegister(){
FIRAuth.auth()?.createUser(withEmail: email, password: password,completion: { (user, error) in
if error != nil
{ print("Error Occured")}
else
{print("Successfully Authenticated")}
})
}
I'm getting compile error, if addTarget removed it compiles successfully
Yes, don't add "()" if there is no param
button.addTarget(self, action:#selector(handleRegister), for: .touchUpInside).
and if you want to get the sender
button.addTarget(self, action:#selector(handleRegister(_:)), for: .touchUpInside).
func handleRegister(sender: UIButton){
//...
}
Edit:
button.addTarget(self, action:#selector(handleRegister(_:)), for: .touchUpInside)
no longer works, you need to replace _ in the selector with a variable name you used in the function header, in this case it would be sender, so the working code becomes:
button.addTarget(self, action:#selector(handleRegister(sender:)), for: .touchUpInside)
Try this with Swift 4
buttonSection.addTarget(self, action: #selector(actionWithParam(_:)), for: .touchUpInside)
#objc func actionWithParam(sender: UIButton){
//...
}
buttonSection.addTarget(self, action: #selector(actionWithoutParam), for: .touchUpInside)
#objc func actionWithoutParam(){
//...
}
Try this
button.addTarget(self, action:#selector(handleRegister()), for: .touchUpInside).
Just add parenthesis with name of method.
Also you can refer link : Value of type 'CustomButton' has no member 'touchDown'
let button: UIButton = UIButton()
button.setImage(UIImage(named:"imagename"), for: .normal)
button.addTarget(self, action:#selector(YourClassName.backAction(_sender:)), for: .touchUpInside)
button.frame = CGRect.init(x: 5, y: 100, width: 45, height: 45)
view.addSubview(button)
#objc public func backAction(_sender: UIButton) {
}
Try with swift 3
cell.TaxToolTips.tag = indexPath.row
cell.TaxToolTips.addTarget(self, action: #selector(InheritanceTaxViewController.displayToolTipDetails(_:)), for:.touchUpInside)
#objc func displayToolTipDetails(_ sender : UIButton) {
print(sender.tag)
let tooltipString = TaxToolTipsArray[sender.tag]
self.displayMyAlertMessage(userMessage: tooltipString, status: 202)
}
In swift 3 use this -
object?.addTarget(objectWhichHasMethod, action: #selector(classWhichHasMethod.yourMethod), for: someUIControlEvents)
For example(from my code) -
self.datePicker?.addTarget(self, action:#selector(InfoTableViewCell.datePickerValueChanged), for: .valueChanged)
Just give a : after method name if you want the sender as parameter.
Try this with Swift 3
button.addTarget(self, action:#selector(ClassName.handleRegister(sender:)), for: .touchUpInside)
Good luck!
The poster's second comment from September 21st is spot on. For those who may be coming to this thread later with the same problem as the poster, here is a brief explanation. The other answers are good to keep in mind, but do not address the common issue encountered by this code.
In Swift, declarations made with the let keyword are constants. Of course if you were going to add items to an array, the array can't be declared as a constant, but a segmented control should be fine, right?! Not if you reference the completed segmented control in its declaration.
Referencing the object (in this case a UISegmentedControl, but this also happens with UIButton) in its declaration when you say .addTarget and let the target be self, things crash. Why? Because self is in the midst of being defined. But we do want to define behaviour as part of the object... Declare it lazily as a variable with var. The lazy fools the compiler into thinking that self is well defined - it silences your compiler from caring at the time of declaration. Lazily declared variables don't get set until they are first called. So in this situation, lazy lets you use the notion of self without issue while you set up the object, and then when your object gets a .touchUpInside or .valueChanged or whatever your 3rd argument is in your .addTarget(), THEN it calls on the notion of self, which at that point is fully established and totally prepared to be a valid target. So it lets you be lazy in declaring your variable. In cases like these, I think they could give us a keyword like necessary, but it is generally seen as a lazy, sloppy practice and you don't want to use it all over your code, though it may have its place in this sort of situation. What it
There is no lazy let in Swift (no lazy for constants).
Here is the Apple documentation on lazy.
Here is the Apple on variables and constants. There is a little more in their Language Reference under Declarations.
Instead of
let loginRegisterButton:UIButton = {
//... }()
Try:
lazy var loginRegisterButton:UIButton = {
//... }()
That should fix the compile error!!!
the Demo from Apple document. https://developer.apple.com/documentation/swift/using_objective-c_runtime_features_in_swift
import UIKit
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// without parameter style
let action = #selector(MyViewController.tappedButton)
// with parameter style
// #selector(MyViewController.tappedButton(_:))
myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
}
#objc func tappedButton(_ sender: UIButton?) {
print("tapped button")
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}

How can I add some func to button?

I have a function, setupGame(). When I press the play again button, the setupGame() function should be called. Where should I add this function?
let playAgain: UIButton = UIButton(frame: CGRectMake(-10, 400, 400, 150))
func setupGame() {
score = 0
physicsWorld.gravity = CGVectorMake(5, 5)
}
func buttonPressed(sender: UIButton) {
}
playAgain.setTitle("Play Again", forState: UIControlState.Normal)
playAgain.titleLabel!.font = UIFont(name: "Helvetica", size: 50)
playAgain.addTarget(self, action: "buttonPressed:", forControlEvents: .TouchUpInside)
playAgain.tag = 1
self.view!.addSubview(playAgain)
If you want to use your storyboard you should add a button and then drag into your code (Outlet). Check this link of how to create an outlet connection.
Or you could create a button programmatically as you have done and call setupGame.
playAgain.addTarget(self, action: "setupGame", forControlEvents: .TouchUpInside)
Simply replace "buttonPressed:" with "setupGame", and remove the buttonPressed function altogether.
You should make a IBAction instead of
func buttonPressed(sender: UIButton) {
}
but yes this is where the setupGame() function should be called
iBAction buttonPressed(sender:UIButton) {
setupGame()
}
and then just make sure you hook up your button to this function so it can detect the tapped interaction.
To call a function when a button is pressed, you should use UIButton.addTarget, which it looks like you already have. The problem is that you have the wrong action specified.
playAgain.addTarget(
self,
action: "buttonPressed:", // This should be "setupGame"
forControlEvents: .TouchUpInside
)
The action parameter of the .addTarget function essentially points to the function that should be called. The little colon after the name is to indicate that the function should accept the sender of the action as an argument.
Assuming this is being added to a button, helloWorld: corresponds to func helloWorld(sender: UIButton), and helloWorld (notice the missing colon) corresponds to func helloWorld()
So, you should use
func setupGame() {
score = 0
physicsWorld.gravity = CGVectorMake(5, 5)
}
//button code
// Notice how the function above has no arguments,
// so there is no colon in the action parameter of
// this call
playAgain.addTarget(
self, // the function to be called is in this class instance (self)
action: "setupGame", // corresponds to the above setupGame function
forControlEvents: .TouchUpInside
)
//other code

Resources