Прикрепите параметр к действию button.addTarget в Swift

Я пытаюсь передать дополнительный параметр в действие buttonClicked, но не могу определить, какой синтаксис должен быть в Swift.

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

Любой мой метод buttonClicked:

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

Любые идеи?

Спасибо за вашу помощь.

Ответ 1

Вы не можете передавать пользовательские параметры в 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")
}

Ответ 2

Если вы хотите отправить дополнительные параметры методу buttonClicked, например indexPath или urlString, вы можете подклассифицировать UIButton:

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

Обязательно измените класс кнопки в инспекторе идентификации на subclassedUIButton. Вы можете получить доступ к параметрам внутри метода buttonClicked с помощью sender.indexPath или sender.urlString.

Примечание. Если ваша кнопка находится внутри ячейки, вы можете установить значение этих дополнительных параметров в методе cellForRowAtIndexPath (где кнопка создана).

Ответ 3

Я ценю всех, кто говорит теги использования, но на самом деле вам нужно расширить класс 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:")) (ПРИМЕЧАНИЕ. Двоеточие ":" в 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"] ?? "")
}

Вы делаете это один раз и используете его во всем своем проекте (вы даже можете заставить дочерний класс иметь общий "объект" и поместить все, что вам нравится, в кнопку!). Или используйте приведенный выше пример, чтобы добавить неиссякаемое количество параметров key/string в кнопку. Действительно полезно для включения таких вещей, как URL-адреса, подтверждение методологии сообщений и т.д.

В стороне, важно, чтобы сообщество SO осознало это, существует целая генерация плохой практики, которая сокращается в Интернете по тревожному числу программистов, которые не понимают/не учат/не упускают точку концепции object extensions

Ответ 4

Для Swift 3.0 вы можете использовать следующие

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

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

}

Ответ 5

В Swift 3 сделайте селектор таким:

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

И поймайте событие следующим образом:

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

}

Ответ 6

Swift 4.0 (здесь мы снова и снова)

Вызываемое действие должно быть отмечено таким образом, потому что это синтаксис для быстрой функции для экспорта функций в объектный язык c.

@objc func deleteAction(sender: UIButton) {
}

создайте рабочую кнопку:

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

Ответ 7

Swift 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.

Ответ 8

Если у вас есть петля таких кнопок, как я, вы можете попробовать что-то вроде этого

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]

}

Ответ 9

Для Swift 2.X и выше

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

Ответ 10

Код 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 и использовать его как параметр в функции.

Ответ 11

Код 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)
}