Como definir a ação para um UIBarButtonItem em Swift

86

Como a ação para um UIBarButtonItem personalizado no Swift pode ser definida?

O código a seguir coloca com sucesso o botão na barra de navegação:

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

Agora, eu gostaria de ligar func sayHello() { println("Hello") }quando o botão for tocado. Meus esforços até agora:

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

e..

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

e..

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

Observe que sayHello()aparece no intellisense, mas não funciona.

Obrigado pela ajuda.

EDITAR: Para a posteridade, as seguintes obras:

var b = UIBarButtonItem(title: "Continue", style: .Plain, target: self, action:"sayHello")
kmiklas
fonte
4
você passa os seletores rapidamente apenas colocando o seletor em uma string,action: "sayHello"
Jiaaro
Muito obrigado. Estou sob pressão para divulgar isso e estava ficando frustrado.
kmiklas
1
Esta pergunta foi marcada anteriormente como uma duplicata de @selector () no Swift? . No entanto, esta pergunta pergunta especificamente sobre UIBarButtonItemenquanto a outra não. Exigir que iniciantes generalizem todos os usos de selectorpode ser difícil para eles, então estou removendo o status duplicado para que as pessoas possam manter esta questão atualizada.
Suragch

Respostas:

157

A partir do Swift 2.2, existe uma sintaxe especial para os seletores verificados no tempo do compilador. Ele usa a sintaxe: #selector(methodName).

Swift 3 e posterior:

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

func sayHello(sender: UIBarButtonItem) {
}

Se você não tiver certeza de como deve ser o nome do método, há uma versão especial do comando de cópia que é muito útil. Coloque o cursor em algum lugar no nome do método base (por exemplo, diga Olá) e pressione Shift+ Control+ Option+ C. Isso coloca o 'Nome do símbolo' no teclado para ser colado. Se você também segurá- Commandlo, copiará o 'Nome do símbolo qualificado' que também incluirá o tipo.

Swift 2.3:

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

func sayHello(sender: UIBarButtonItem) {
}

Isso ocorre porque o primeiro nome de parâmetro não é necessário no Swift 2.3 ao fazer uma chamada de método.

Você pode aprender mais sobre a sintaxe em swift.org aqui: https://swift.org/blog/swift-2-2-new-features/#compile-time-checked-selectors

Drewag
fonte
11
Só para mencionar que a função de ação não pode ser privada ! Não tenho certeza do motivo, mas sempre recebo um erro caso forneça o nome de alguma função privada
maddob
Eu entendi: "não implementa o métodoSignatureForSelector"
AlamoPS
1
@AlamoPS Se você estiver usando a 2ª versão com dois pontos, você precisará certificar-se de que os tipos de parâmetro de função correspondem a qualquer ação que você está manipulando.
Jason
1
@RyanForsyth A string realmente é traduzida nos Selector("sayHello")bastidores por Swift de qualquer maneira.
fatuhoku
2
Esta resposta está desatualizada.
Dan Loewenherz
33

Exemplo Swift 4/5

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

@objc func buttonClicked(sender: UIBarButtonItem) {
        
}
norbDEV
fonte
5
Isso é correto, para Swift 4 você precisa adicionar @objcà declaração da função. Até o Swift 4, isso era inferido implicitamente.
Jonathan Cabrera de
1
button.target = self
Mahesh
@Mahesh não precisa definir a meta
norbDEV
A meta @norbDEV é necessária para Swift 5
Biasi Wiga
2

Exemplo programático de Swift 5 e iOS 13+

  1. Você deve marcar sua função com @objc, veja o exemplo abaixo!
  2. Sem parênteses após o nome da função! Basta usar #selector(name).
  3. privateou publicnão importa; você pode usar privado.

Exemplo de Código

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
fonte
0

Que este aqui ajude um pouco mais

Suponha que se você quiser fazer o botão da barra em um arquivo separado (para abordagem modular) e quiser devolver o seletor ao seu viewcontroller, você pode fazer assim: -

seu arquivo utilitário

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];
    }
}

Então faça uma classe SuperviewController e defina a mesma função nela.

class SuperViewController: UIViewController {

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

    }
}

e em nosso viewController base (que herda sua classe SuperviewController) sobrescreve a mesma função

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

Agora, apenas herde o SuperViewController em qualquer classe que você deseja neste barbutton.

Obrigado pela leitura

Anurag Bhakuni
fonte
0

Swift 5

se você criou UIBarButtonItem no Interface Builder e conectou a saída ao item e deseja vincular o seletor de forma programática.

Não se esqueça de definir o alvo e o seletor.

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

@objc private func moveToAddAppointment() {
     self.presenter.goToCreateNewAppointment()
}
Mahesh
fonte