在Swift中将参数附加到button.addTarget动作


101

我试图将一个额外的参数传递给buttonClicked动作,但是无法计算出Swift中的语法。

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

任何我的buttonClicked方法:

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

有任何想法吗?

谢谢你的帮助。


1
请参阅此链接,以获取详细的答案和最佳实践
片面

该问题没有一个好的答案,因为它已经描述了有问题的体系结构。您不需要额外的参数。在体系结构中,需要附加参数是一个问题。
苏珊(Sulthan)2013年

WARNING TO INTERNET: please check out my answer at the bottom
Heelis先生

Answers:


170

您无法在中传递自定义参数addTarget:。另一种方法是设置tagbutton 的属性并根据标签进行工作。

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

或对于Swift 2.2及更高版本:

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

现在基于tag属性做逻辑

@objc func buttonClicked(sender:UIButton)
{
    if(sender.tag == 5){

        var abc = "argOne" //Do something for tag 5
    }
    print("hello")
}

4
嗨,如果我想在tableView中获取indexPath或按钮的单元格,可以吗?
NKurapati 2015年

1
提示:不要将方法设为私有。
OhadM

2
好像它的类型只能是Int。没有其他的。
scaryguy

2
如果我想一起传递行和节怎么办?
Yestay Muratov

3
请注意,尽管有118次投票(并且还在不断增加),但这是错误的方法
先生

79

如果要将其他参数发送到buttonClicked方法,例如indexPath或urlString,则可以将UIButton子类化:

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

确保将身份检查器中按钮的类更改为subclassedUIButton。您可以使用sender.indexPath或在buttonClicked方法内访问参数sender.urlString

注意:如果按钮在单元格内,则可以在cellForRowAtIndexPath方法(创建按钮的位置)中设置这些附加参数的值。


5
这是对我有用的唯一方法。但是我很好奇,这是反模式吗?
scaryguy

1
我认为这是最好的方法
Duy Hoang

29

我很感谢每个人都说使用标签,但实际上您需要扩展UIButton类并在其中简单地添加对象。

标签是解决这一问题的绝望途径。像这样扩展UIButton(在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)
    }
}

那么您的电话可能会被致电(注意中的冒号“:” 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"

然后终于在这里抓住了一切

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

您只需执行一次并在整个项目中使用它(您甚至可以使子类具有通用的“对象”,然后将您喜欢的任何内容放到按钮中!)。或使用上面的示例在按钮中放入无穷无尽的键/字符串参数。.对于包括url,确认消息方法等内容非常有用

SO顺便说一句,社区意识到这一点很重要,这是一整代的不良习惯,因为大量的不了解/未曾教过/遗忘了这一点的程序员在互联网上拖来溜去。的概念object extensions


10

对于Swift 3.0,您可以使用以下命令

button.addTarget(self, action: #selector(YourViewController.YourMethodName(_:)), for:.touchUpInside)

func YourMethodName(_ sender : UIButton) {
    print(sender.tag)

}

9

斯威夫特4.2

结果:

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")
}

在文件中,UIButton+Events.swift我为此创建了一个扩展方法,UIButton该方法将a绑定UIControl.Event到名为的完成处理程序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)
    }
}

我之所以使用自定义类来绑定事件,是为了能够在以后取消按钮初始化时释放该引用。这样可以防止可能发生的内存泄漏。在UIButton其扩展名中这是不可能的,因为不允许我实现属性或deinit方法。


2

如果您有像我这样的按钮循环,可以尝试这样的操作

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

Swift 4.0代码(在此我们再次进行)

被调用的动作应该这样标记,因为这是将函数导出为目标c语言的swift函数的语法。

@objc func deleteAction(sender: UIButton) {
}

创建一些工作按钮:

let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector( 
MyController.deleteAction(sender:)), for: .touchUpInside)

感谢分享。这可行,但是用@objc标记它是不直观的。您能解释一下原因吗?
rawbee '17

@rawbee同意这是违反直觉的。这个问题的背景更多:stackoverflow.com/questions/44390378/…–
Mikrasya

1

Swift 5.0代码

我使用theButton.tag,但是如果我有很多类型的选项,它的开关盒会很长。

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

@objc func theFunc(sender:UIButton){ 
print(sender.frame.name)
}

0

对于Swift 2.X及更高版本

button.addTarget(self,action:#selector(YourControllerName.buttonClicked(_:)),
                         forControlEvents:.TouchUpInside)

0

Swift 3.0代码

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
}

您可以在“ userinfo”中发送值,并将其用作函数中的参数。


0

这更是一个重要的评论。开箱即用地共享sytanx的引用。对于黑客解决方案,请查看其他答案。

根据Apple的文档,“操作方法定义”必须是这三个之一。其他任何事情都不可接受。

@IBAction func doSomething()
@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.