Fügen Sie den Parameter der Aktion button.addTarget in Swift hinzu

100

Ich versuche, einen zusätzlichen Parameter an die Aktion buttonClicked zu übergeben, kann jedoch nicht herausfinden, wie die Syntax in Swift lauten soll.

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

Jede meiner buttonClicked-Methoden:

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

Hat jemand irgendwelche Ideen?

Danke für Ihre Hilfe.

iphaaw
quelle
1
Unter diesem Link finden Sie eine detaillierte Antwort und Best Practice
Blatt
Die Frage hat keine gute Antwort, da sie bereits eine problematische Architektur beschreibt. Sie benötigen keinen zusätzlichen Parameter. Die Notwendigkeit eines zusätzlichen Parameters ist ein Problem in Ihrer Architektur.
Sulthan
WARNING TO INTERNET: please check out my answer at the bottom
Herr Heelis

Antworten:

170

Sie können keine benutzerdefinierten Parameter in übergeben. addTarget:Eine Alternative besteht darin, die tagEigenschaft der Schaltfläche festzulegen und basierend auf dem Tag zu arbeiten.

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

Oder für Swift 2.2 und höher:

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

Führen Sie nun eine Logik aus, die auf der tagEigenschaft basiert

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

        var abc = "argOne" //Do something for tag 5
    }
    print("hello")
}
Codester
quelle
4
Hallo, wenn ich indexPath oder eine Zelle der Schaltfläche in tableView erhalten möchte, ist das möglich?
NKurapati
1
Hier ist ein Hinweis: Machen Sie die Methode nicht privat.
OhadM
2
Scheint, als ob es nur ein Typ sein kann Int. Nichts anderes.
Scaryguy
2
Was ist, wenn ich Zeile und Abschnitt zusammen übergeben möchte?
Yestay Muratov
3
Nur damit Sie wissen, trotz 118 Gegenstimmen (und Zählen) ist dies der falsche Weg, dies zu tun
Herr Heelis
79

Wenn Sie zusätzliche Parameter an die buttonClicked-Methode senden möchten, z. B. einen indexPath oder einen urlString, können Sie den UIButton in Unterklassen unterteilen:

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

Stellen Sie sicher, dass Sie die Klasse der Schaltfläche im Identitätsinspektor in die Unterklasse UIButton ändern. Sie können mit sender.indexPathoder auf die Parameter in der buttonClicked-Methode zugreifen sender.urlString.

Hinweis: Wenn sich Ihre Schaltfläche in einer Zelle befindet, können Sie den Wert dieser zusätzlichen Parameter in der cellForRowAtIndexPath-Methode festlegen (in der die Schaltfläche erstellt wird).

Uclagamer
quelle
5
Dies war der einzige Weg, der für mich funktioniert hat. Aber ich bin neugierig, ist das Anti-Muster oder nicht?
Scaryguy
1
Dies ist der beste Weg, denke ich
Duy Hoang
29

Ich schätze jeden, der sagt, Tags verwenden, aber wirklich müssen Sie die UIButton-Klasse erweitern und einfach das Objekt dort hinzufügen.

Tags sind ein hoffnungsloser Weg, um dies zu umgehen. Erweitern Sie den UIButton wie folgt (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)
    }
}

dann kann Ihr Anruf ein Anruf sein (HINWEIS DER Doppelpunkt ":" 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"

dann endlich alles hier fangen

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

Sie tun dies einmal und verwenden es während Ihres gesamten Projekts (Sie können sogar dafür sorgen, dass die untergeordnete Klasse ein generisches "Objekt" hat und alles, was Sie möchten, in die Schaltfläche einfügt!). Oder verwenden Sie das obige Beispiel, um eine unerschöpfliche Anzahl von Schlüssel- / Zeichenfolgenparametern in die Schaltfläche einzufügen. Wirklich nützlich, um Dinge wie URLs einzuschließen, die Nachrichtenmethode zu bestätigen usw.

Abgesehen davon ist es wichtig, dass die SOCommunity erkennt, dass eine ganze Generation von schlechten Praktiken im Internet von einer alarmierenden Anzahl von Programmierern abgeschnitten und eingefügt wird, die den Punkt nicht verstehen / nicht unterrichtet / verpasst haben das Konzept vonobject extensions

Herr Heelis
quelle
10

Für Swift 3.0 können Sie Folgendes verwenden

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

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

}
MK_iOS
quelle
8

Swift 4.2

Ergebnis:

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 der Datei UIButton+Events.swifthabe ich eine Erweiterungsmethode erstellt UIButton, die a UIControl.Eventan einen Completion-Handler mit dem Namen bindet 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)
    }
}

Der Grund, warum ich eine benutzerdefinierte Klasse zum Binden des Ereignisses verwendet habe, besteht darin, dass ich die Referenz später entsorgen kann, wenn die Schaltfläche deintialisiert wird. Dadurch wird verhindert, dass ein möglicher Speicherverlust auftritt. Dies war innerhalb der UIButtonErweiterung nicht möglich , da ich weder eine Eigenschaft noch die deinitMethode implementieren darf .

Lloyd Keijzer
quelle
2

Wenn Sie eine Reihe von Schaltflächen wie ich haben, können Sie so etwas ausprobieren

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]

}
Brahimm
quelle
2

Swift 4.0 Code (Jetzt geht es wieder los)

Die aufgerufene Aktion sollte wie folgt markiert sein, da dies die Syntax für die schnelle Funktion zum Exportieren von Funktionen in die objektive c-Sprache ist.

@objc func deleteAction(sender: UIButton) {
}

Erstellen Sie eine Arbeitsschaltfläche:

let deleteButton = UIButton(type: .roundedRect)
deleteButton.setTitle("Delete", for: [])
deleteButton.addTarget(self, action: #selector( 
MyController.deleteAction(sender:)), for: .touchUpInside)
Karsten
quelle
Danke für das Teilen. Dies funktioniert, aber das Markieren mit @objc fühlt sich nicht intuitiv an. Können Sie die Gründe dafür erklären?
Rawbee
@rawbee Stimmen Sie zu, dass dies nicht intuitiv ist. Diese Frage hat mehr Hintergrund: stackoverflow.com/questions/44390378/…
Mikrasya
1

Schneller 5.0-Code

Ich benutze theButton.tag, aber wenn ich viele Optionen habe, ist es ein sehr langer Schalterfall.

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

.

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

Für Swift 2.X und höher

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

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

Sie können einen Wert in 'userinfo' senden und diesen als Parameter in der Funktion verwenden.

krish
quelle
0

Dies ist eher ein wichtiger Kommentar. Teilen von Referenzen von Sytanx, die sofort akzeptabel sind. Für Hack-Lösungen schauen Sie sich andere Antworten an.

Gemäß den Apple-Dokumenten müssen die Definitionen der Aktionsmethoden eine dieser drei sein. Alles andere wird nicht akzeptiert.

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