Jak ustawić akcję dla UIBarButtonItem w Swift

86

Jak można ustawić akcję dla niestandardowego elementu UIBarButtonItem w języku Swift?

Poniższy kod pomyślnie umieszcza przycisk na pasku nawigacyjnym:

var b = UIBarButtonItem(title: "Continue", style: .Plain, target: self, action:nil)
self.navigationItem.rightBarButtonItem = b

Teraz chciałbym zadzwonić func sayHello() { println("Hello") }po dotknięciu przycisku. Moje dotychczasowe wysiłki:

var b = UIBarButtonItem(title: "Continue", style: .Plain, target: self, action:sayHello:)
// also with `sayHello` `sayHello()`, and `sayHello():`

i..

var b = UIBarButtonItem(title: "Continue", style: .Plain, target: self, action:@selector(sayHello:))
// also with `sayHello` `sayHello()`, and `sayHello():`

i..

var b = UIBarButtonItem(title: "Continue", style: .Plain, target: self, action:@selector(self.sayHello:))
// also with `self.sayHello` `self.sayHello()`, and `self.sayHello():`

Zauważ, że sayHello()pojawia się w trybie Intellisense, ale nie działa.

Dzięki za pomoc.

EDYCJA: Dla potomnych następujące prace:

var b = UIBarButtonItem(title: "Continue", style: .Plain, target: self, action:"sayHello")
kmiklas
źródło
4
szybko mijasz selektory, po prostu umieszczając selektor w ciągu,action: "sayHello"
Jiaaro
Dziękuję bardzo. Jestem pod presją, żeby to z siebie wyrzucić i zaczynałem się frustrować.
kmiklas
1
To pytanie było wcześniej oznaczone jako duplikat @selector () w Swift? . Jednak to pytanie dotyczy konkretnie, UIBarButtonItempodczas gdy drugie nie. Wymaganie od początkujących uogólniania wszystkich zastosowań selectormoże być dla nich trudne, więc usuwam status zduplikowany, aby ludzie mogli aktualizować to pytanie.
Suragch

Odpowiedzi:

157

Od wersji Swift 2.2 istnieje specjalna składnia dla selektorów sprawdzanych w czasie kompilacji. Używa składni: #selector(methodName).

Swift 3 i nowsze:

var b = UIBarButtonItem(
    title: "Continue",
    style: .plain,
    target: self,
    action: #selector(sayHello(sender:))
)

func sayHello(sender: UIBarButtonItem) {
}

Jeśli nie jesteś pewien, jak powinna wyglądać nazwa metody, istnieje specjalna wersja polecenia kopiowania, która jest bardzo pomocna. Umieść kursor gdzieś w nazwie metody bazowej (np. SayHello) i naciśnij Shift+ Control+ Option+ C. To powoduje umieszczenie „nazwy symbolu” na klawiaturze do wklejenia. Jeśli również Commandgo posiadasz , skopiuje „kwalifikowaną nazwę symbolu”, która będzie zawierała również typ.

Swift 2.3:

var b = UIBarButtonItem(
    title: "Continue",
    style: .Plain,
    target: self,
    action: #selector(sayHello(_:))
)

func sayHello(sender: UIBarButtonItem) {
}

Dzieje się tak, ponieważ pierwsza nazwa parametru nie jest wymagana w Swift 2.3 podczas wywoływania metody.

Możesz dowiedzieć się więcej o składni na swift.org tutaj: https://swift.org/blog/swift-2-2-new-features/#compile-time-checked-selectors

drewag
źródło
11
Wystarczy wspomnieć, że funkcja akcji nie może być prywatna ! Nie bardzo wiem dlaczego, ale zawsze
pojawia
Mam to: „nie implementuje metody methodSignatureForSelector”
AlamoPS,
1
@AlamoPS Jeśli używasz drugiej wersji z dwukropkiem, musisz się upewnić, że typy parametrów funkcji pasują do tego dla każdej wykonywanej czynności.
Jason
1
@RyanForsyth Ciąg i tak jest tłumaczony Selector("sayHello")za kulisami przez Swift.
fatuhoku
2
Ta odpowiedź jest nieaktualna.
Dan Loewenherz
33

Przykład Swift 4/5

button.target = self
button.action = #selector(buttonClicked(sender:))

@objc func buttonClicked(sender: UIBarButtonItem) {
        
}
norbDEV
źródło
5
To prawda, dla Swift 4 musisz dodać @objcdo deklaracji funkcji. Aż do wersji Swift 4 wywnioskowano to niejawnie.
Jonathan Cabrera
1
button.target = self
Mahesh
@Mahesh nie musi ustawiać celu
norbDEV
Cel @norbDEV jest potrzebny dla Swift 5
Biasi Wiga
2

Przykład automatyzacji Swift 5 i iOS 13+

  1. Musisz oznaczyć swoją funkcję @objc, patrz poniższy przykład!
  2. Po nazwie funkcji nie ma nawiasów! Po prostu użyj #selector(name).
  3. privatelub publicnie ma znaczenia; możesz użyć prywatnego.

Przykład kodu

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    let menuButtonImage = UIImage(systemName: "flame")
    let menuButton = UIBarButtonItem(image: menuButtonImage, style: .plain, target: self, action: #selector(didTapMenuButton))
    navigationItem.rightBarButtonItem = menuButton
}

@objc public func didTapMenuButton() {
    print("Hello World")
}
Zorayr
źródło
0

Niech ten pomoże trochę więcej

Załóżmy, że jeśli chcesz utworzyć przycisk paska w oddzielnym pliku (dla podejścia modułowego) i chcesz zwrócić selektor z powrotem do kontrolera widoku, możesz zrobić to w następujący sposób: -

plik narzędziowy

class GeneralUtility {

    class func customeNavigationBar(viewController: UIViewController,title:String){
        let add = UIBarButtonItem(title: "Play", style: .plain, target: viewController, action: #selector(SuperViewController.buttonClicked(sender:)));  
      viewController.navigationController?.navigationBar.topItem?.rightBarButtonItems = [add];
    }
}

Następnie utwórz klasę SuperviewController i zdefiniuj w niej tę samą funkcję.

class SuperViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
            // Do any additional setup after loading the view.
    }
    @objc func buttonClicked(sender: UIBarButtonItem) {

    }
}

iw naszym podstawowym viewController (który dziedziczy twoją klasę SuperviewController) przesłania tę samą funkcję

import UIKit

class HomeViewController: SuperViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func viewWillAppear(_ animated: Bool) {
        GeneralUtility.customeNavigationBar(viewController: self,title:"Event");
    }

    @objc override func buttonClicked(sender: UIBarButtonItem) {
      print("button clicked")    
    } 
}

Teraz po prostu odziedzicz SuperViewController w dowolnej klasie, w której chcesz ten barbutton.

Dzięki za przeczytanie

Anurag Bhakuni
źródło
0

Szybki 5

jeśli utworzyłeś UIBarButtonItemw Interface Builder i podłączyłeś outlet do elementu i chcesz programowo powiązać selektor.

Nie zapomnij ustawić celu i selektora.

addAppointmentButton.action = #selector(moveToAddAppointment)
addAppointmentButton.target = self

@objc private func moveToAddAppointment() {
     self.presenter.goToCreateNewAppointment()
}
Mahesh
źródło