2015-11-11 8 views
15

Ich habe mich nur gefragt, ob es möglich war, eine Funktion an eine Schaltfläche Aktion übergeben (die in der Regel ein Selektor ist).Swift Verwendung Selektor-Argument wie eine Schließung

Zum Beispiel normalerweise würde ich sagen:

UIBarButtonItem(title: "Press", style: .Done, target: self, action: "functionToCall") 

func functionToCall() { 
    // Do something 
} 

Aber ich frage mich, ob es möglich ist, so etwas wie zu tun:

UIBarButtonItem(title: "Press", style: .Done, target: self, action: { 
    // Do Something 
}) 

Grund ich tun möchte, ist dies, weil meine Funktion ist Super einfach und es sieht so aus als wäre es ordentlicher und Swift-artiger was mit dem Schwerpunkt auf Verschlüsse setzt.

Antwort

0

Leider ist es nicht möglich mit Apple initialisierten Initialisierern. Die Art und Weise, wie dies im Hintergrund funktioniert, geschieht mit Reflektion, und das Bereitstellen einer Schließung ist etwas völlig anderes, was derzeit nicht unterstützt wird.

Sie könnten in der Lage sein, eine benutzerdefinierte Lösung mit etwas Hacking zu erstellen, oder Apple könnte das in Zukunft einführen.

1

Ein Post auf Reddit erklärt, eine Lösung für diesen mit einem benutzerdefinierten Komponente - https://www.reddit.com/r/swift/comments/3fjzap/creating_button_action_programatically_using

es zu benutzen, obwohl ich als durch den Storyboard-Knopf programmatisch eher hinzuzufügen hatte. Hier war, wie ich es gemacht habe.

let tempVariableIWantToReference = "Classy" 

navigationTitle.leftBarButtonItem = BlockBarButtonItem.init(
    title: "< Back", style: UIBarButtonItemStyle.Plain, 
    actionHandler: {() -> Void in 
     print("Hey I'm in a closure") 
     print("I can even reference temporary variables. \(self.tempVariableIWantToReference)!!!") 
    }) 
10

Hier ist eine aktualisierte Lösung für Swift 3.

class BlockBarButtonItem: UIBarButtonItem { 
    private var actionHandler: ((Void) -> Void)? 

    convenience init(title: String?, style: UIBarButtonItemStyle, actionHandler: ((Void) -> Void)?) { 
    self.init(title: title, style: style, target: nil, action: #selector(barButtonItemPressed)) 
    self.target = self 
    self.actionHandler = actionHandler 
    } 

    convenience init(image: UIImage?, style: UIBarButtonItemStyle, actionHandler: ((Void) -> Void)?) { 
    self.init(image: image, style: style, target: nil, action: #selector(barButtonItemPressed)) 
    self.target = self 
    self.actionHandler = actionHandler 
    } 

    func barButtonItemPressed(sender: UIBarButtonItem) { 
    actionHandler?() 
    } 
} 
+0

funktioniert es für Objective-C Eigenschaft Blöcke? http://stackoverflow.com/questions/42172472/how-to-invoke-objective-c-block-property-in-swift – Aleksandr

+0

Ja sollten Sie in der Lage sein, etwas Ähnliches mit objective-c zu tun. – David

+0

wie du in der Frage unter dem Link sehen kannst, sieht es nicht wie möglich aus. Vielleicht weißt du warum? – Aleksandr

4

Dies ist eine alternative Lösung ohne Subclassing:

extension UIBarButtonItem { 
    private struct AssociatedObject { 
     static var key = "action_closure_key" 
    } 

    var actionClosure: (()->Void)? { 
     get { 
      return objc_getAssociatedObject(self, &AssociatedObject.key) as?()->Void 
     } 
     set { 
      objc_setAssociatedObject(self, &AssociatedObject.key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 
      target = self 
      action = #selector(didTapButton(sender:)) 
     } 
    } 

    @objc func didTapButton(sender: Any) { 
     actionClosure?() 
    } 
} 

Es stützt sich auf die damit verbundenen Objekte aus der Objective-C-Laufzeit Fügen Sie eine Schließ-/Blockeigenschaft hinzu.

Wenn festgelegt, wird das Ziel in sich selbst geändert und der Selektor wird auf eine neue Funktion gesetzt, die den Abschluss aufruft, falls er existiert.

Damit in jedem Moment, den Sie gerade die actionClosure jeder UIBarButtonItem einstellen und erwarten, dass alles, um hier zu arbeiten ist ein Beispiel:

let button = UIBarButtonItem(
    barButtonSystemItem: .action, 
    target: nil, action: nil 
) 
button.actionClosure = { 
    print("hello") 
} 
Verwandte Themen