可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to pass an extra parameter to the buttonClicked action, but cannot work out what the syntax should be in Swift.
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
Any my buttonClicked method:
func buttonClicked(sender:UIButton)
{
println("hello")
}
Anyone any ideas?
Thanks for your help.
回答1:
You cannot pass custom parameters in addTarget:
.One alternative is set the tag
property of button and do work based on the tag.
button.tag = 5
button.addTarget(self, action: "buttonClicked:",
forControlEvents: UIControlEvents.TouchUpInside)
Or for Swift 2.2 and greater:
button.tag = 5
button.addTarget(self,action:#selector(buttonClicked),
forControlEvents:.TouchUpInside)
Now do logic based on tag
property
@objc func buttonClicked(sender:UIButton)
{
if(sender.tag == 5){
var abc = "argOne" //Do something for tag 5
}
print("hello")
}
回答2:
If you want to send additional parameters to the buttonClicked method, for example an indexPath or urlString, you can subclass the UIButton:
class subclassedUIButton: UIButton {
var indexPath: Int?
var urlString: String?
}
Make sure to change the button's 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).
回答3:
I appreciate everyone saying use tags, but really you need to extend the UIButton class and simply add the object there..
Tags are a hopeless way round this. Extend the 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 may be call (NOTE THE 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 one time and use it throughout your project (you can even make the child class have a generic "object" and put whatever you like into the button!). Or use the example above to put an inexhaustible number of key/string params into the button.. Really useful for including things like urls, confirm message methodology etc
As an aside, it's important that the SO
community realise this there is an entire generation of bad practice being cut'n'paste round the internet by an alarming number of programmers who don't understand/haven't been taught/missed the point of the concept of object extensions
回答4:
In Swift 3 make a selector like that:
button.addTarget(self, action: #selector(ViewController.multipleParamSelector(_:secondParams:)), for: .touchUpInside)
And catch the event like that:
func multipleParamSelector(_ sender: AnyObject, secondParams: AnyObject) {
}
回答5:
For Swift 3.0 you can use following
button.addTarget(self, action: #selector(YourViewController.YourMethodName(_:)), for:.touchUpInside)
func YourMethodName(_ sender : UIButton) {
print(sender.tag)
}
回答6:
Swift 4.0 code (Here we go again)
The called action should marked like this because that is the syntax for swift function for exporting functions into objective c language.
@objc func deleteAction(sender: UIButton) {
}
create some working button:
let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector(
MyController.deleteAction(sender:)), for: .touchUpInside)
回答7:
If you have a loop of buttons 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]
}
回答8:
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 file UIButton+Events.swift
I've created an extension method for UIButton
that binds a UIControl.Event
to a completion handler called 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 why I used a custom class for binding the event is to be able to dispose the reference later when the button is deintialised. This will prevent a possible memory leak from occurring. This wasn't possible within the UIButton
its extension, because I'm not allowed to implement a property nor the deinit
method.
回答9:
For Swift 2.X and above
button.addTarget(self,action:#selector(YourControllerName.buttonClicked(_:)),
forControlEvents:.TouchUpInside)
回答10:
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 value in 'userinfo' and use that as parameter in the function.