繁体   English   中英

将参数附加到 Swift 中的 button.addTarget 操作

[英]Attach parameter to button.addTarget action in Swift

我试图将一个额外的参数传递给 buttonClicked 操作,但无法确定 Swift 中的语法应该是什么。

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

任何我的 buttonClicked 方法:

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

有人有什么想法吗?

谢谢你的帮助。

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

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

如果你想向 buttonClicked 方法发送额外的参数,例如 indexPath 或 urlString,你可以子类化 UIButton:

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

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

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

我感谢每个人都说使用标签,但实际上您需要扩展 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的概念

对于 Swift 3.0,您可以使用以下内容

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

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

}

斯威夫特 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创建了一个扩展方法,它将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方法。

在Swift 3中创建一个这样的选择器:

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

并抓住这样的事件:

func multipleParamSelector(_ sender: AnyObject, secondParams: AnyObject) {

}

如果你有像我一样的按钮循环,你可以尝试这样的事情

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]

}

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)

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

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

根据 Apple 的文档,Action Method Definitions必须是这三个中的一个。 其他的都是不接受的。

@IBAction func doSomething()
@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)

对于 Swift 2.X 及更高版本

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

斯威夫特 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”中发送值并将其用作函数中的参数。

button.tag = indexPath.row
button.addTarget(self, action: "buttonClicked:", 
    forControlEvents: UIControlEvents.TouchUpInside)
cell.accessoryView = button;

按钮标签可以帮助您从数组/字典中检索专用记录

可能有点矫枉过正,但你不能为此使用协议吗? 那么就真的不需要传入参数了,因为你应该可以访问符合 class 的属性。

protocol ButtonActionDelegate {
      func buttonClicked()
}

class SomeClassWithSomeButton: ButtonActionDelegate {
      let button = UIButton
      button.addTarget(self, action: "buttonClicked", forControlEvents: UIControlEvents.TouchUpInside)

      func buttonClicked() {
           //Do specific action
          }
}

虽然您不能按照您建议的方式传递参数(使用addTarget ),但您可以使用addAction ,您可以在其中使用您想要的任何参数调用任何其他 function :

let btnAuto = UIButton(type: .system)
    btnAuto.frame = CGRect(x:0, y:0 , width:200, height:20)
    btnAuto.backgroundColor = .blue
    btnAuto.addAction(
        UIAction { _ in
            print("This gets printed when the button is pressed")
            dothis(param1, param2)
        }, for: .touchUpInside)
    self.view.addSubview(btnAuto)

当您以编程方式创建一系列按钮并希望每个按钮执行不同的操作时,这特别有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM