web-dev-qa-db-fra.com

Attache le paramètre à l'action button.addTarget dans Swift

J'essaie de passer un paramètre supplémentaire à l'action buttonClicked, mais je ne peux pas déterminer la syntaxe à utiliser dans Swift.

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

Toute ma méthode buttonClicked:

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

Quelqu'un a des idées?

Merci de votre aide.

86
iphaaw

Vous ne pouvez pas transmettre de paramètres personnalisés dans addTarget:. Une alternative consiste à définir la propriété tag de button et à travailler en fonction de la balise.

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

Ou pour Swift 2.2 et supérieur:

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

Maintenant, faites la logique basée sur la propriété tag

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

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

Si vous souhaitez envoyer des paramètres supplémentaires à la méthode buttonClicked, par exemple indexPath ou urlString, vous pouvez sous-classer UIButton:

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

Assurez-vous de changer la classe du bouton dans l'inspecteur d'identité en sous-classe UIButton. Vous pouvez accéder aux paramètres de la méthode buttonClicked à l'aide de sender.indexPath ou sender.urlString.

Remarque: Si votre bouton est à l'intérieur d'une cellule, vous pouvez définir la valeur de ces paramètres supplémentaires dans la méthode cellForRowAtIndexPath (où le bouton est créé).

69
uclagamer

J'apprécie que tout le monde dise utiliser des balises, mais vous devez vraiment étendre la classe UIButton et simplement y ajouter l'objet.

Les étiquettes sont un moyen sans espoir de contourner cela. Étendre le UIButton comme ceci (dans 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)
    }
}

alors votre appel peut être appelé (NOTE THE deux points ":" dans 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"

puis enfin attraper tout cela ici

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

Vous faites cela une fois et vous l'utilisez tout au long de votre projet (vous pouvez même donner à la classe enfant un objet générique et mettre ce que vous voulez dans le bouton!). Ou utilisez l’exemple ci-dessus pour mettre un nombre inépuisable de paramètres clé/chaîne dans le bouton. Vraiment utile pour inclure des éléments tels que des URL, confirmer la méthodologie du message, etc.

En passant, il est important que la communauté SO réalise cela. Il existe toute une génération de mauvaises pratiques coupées autour de l'Internet par un nombre alarmant de programmeurs qui ne comprennent pas/qui n'ont pas N'avez-vous pas appris/oublié le concept de object extensions

22
Mr Heelis

Pour Swift 3.0, vous pouvez utiliser ce qui suit

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

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

}
9
MK_iOS

Swift 4.2

Résultat:

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

Dans le fichier UIButton+Events.Swift j'ai créé une méthode d'extension pour UIButton qui lie un UIControl.Event à un gestionnaire d'achèvement appelé 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)
    }
}

La raison pour laquelle j'ai utilisé une classe personnalisée pour lier l'événement est de pouvoir disposer de la référence ultérieurement lorsque le bouton est désintialisé. Cela évitera une éventuelle fuite de mémoire. Cela n'était pas possible dans l'extension UIButton, car je ne suis pas autorisé à implémenter une propriété ni la méthode deinit.

6
Lloyd Keijzer

Dans Swift 3, créez un sélecteur comme celui-ci:

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

Et attrapez l'événement comme ça:

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

}
4
Riajur Rahman

code Swift 4.0 (nous y revoilà)

L'action appelée doit être marquée comme ceci car c'est la syntaxe de la fonction Swift pour exporter des fonctions en langage Objective C.

@objc func deleteAction(sender: UIButton) {
}

créer un bouton de travail:

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

Si vous avez une boucle de boutons comme moi, vous pouvez essayer quelque chose comme ça

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
brahimm

Swift 5.0 code

J'utilise theButton.tag mais si j'ai beaucoup d'options, son cas sera très long.

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

.

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

Pour Swift 2.X et ci-dessus

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

code Swift 3.

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
}

Vous pouvez envoyer une valeur dans 'userinfo' et l'utiliser comme paramètre dans la fonction.

0
krish