tutorial - @selector() no Swift?




timer example swift 4 (15)

Além disso, se a sua classe (Swift) não descer de uma classe Objective-C, então você deve ter dois pontos no final da string de nome do método de destino e você deve usar a propriedade @objc com seu método de destino, por exemplo

var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))

@objc func method() {
    // Something cool here   
} 

caso contrário, você receberá um erro "Seletor não reconhecido" no tempo de execução.

Eu estou tentando criar um NSTimer no Swift mas estou tendo alguns problemas.

NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)

test() é uma função da mesma classe.

Eu recebo um erro no editor:

Não foi possível encontrar uma sobrecarga para o 'init' que aceita os argumentos fornecidos

Quando eu mudo o selector: test() para selector: nil o erro desaparece.

Eu tentei:

  • selector: test()
  • selector: test
  • selector: Selector(test())

Mas nada funciona e não consigo encontrar uma solução nas referências.


Alterar como uma simples nomeação de string no método que chama a sintaxe do seletor

var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)

Depois disso, digite func test ().


Apenas no caso de alguém ter o mesmo problema que tive com o NSTimer, onde nenhuma das outras respostas resolveu o problema, é realmente importante mencionar que, se você estiver usando uma classe que não herde do NSObject diretamente ou no fundo da hierarquia ( Por exemplo, arquivos swift criados manualmente), nenhuma das outras respostas funcionará mesmo quando especificado da seguinte maneira:

let timer = NSTimer(timeInterval: 1, target: self, selector: "test", 
                    userInfo: nil, repeats: false)
func test () {}

Sem alterar nada além de apenas tornar a classe herdada do NSObject, parei de receber o erro "Unrecognized selector" e obtive minha lógica funcionando como esperado.


Aqui está um exemplo rápido de como usar a classe Selector no Swift:

override func viewDidLoad() {
    super.viewDidLoad()

    var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
    self.navigationItem.rightBarButtonItem = rightButton
}

func method() {
    // Something cool here   
}

Observe que, se o método transmitido como uma string não funcionar, ele falhará no tempo de execução, não no tempo de compilação e interromperá seu aplicativo. Seja cuidadoso


Eu achei muitas dessas respostas úteis, mas não estava claro como fazer isso com algo que não era um botão. Eu estava adicionando um reconhecedor de gestos a um UILabel rapidamente e me esforcei, então aqui está o que eu achei que funcionou para mim depois de ler tudo acima:

let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: "labelTapped:")

Onde o "Seletor" foi declarado como:

func labelTapped(sender: UILabel) { }

Observe que é público e que não estou usando a sintaxe Selector (), mas é possível fazer isso também.

let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: Selector("labelTapped:"))

O próprio Swift não usa seletores - vários padrões de projeto que fazem uso de seletores no Objective-C funcionam de maneira diferente no Swift. (Por exemplo, use encadeamento opcional em tipos de protocolo ou is / as testes em vez de respondsToSelector: e use encerramentos sempre que possível, em vez de performSelector: para melhor segurança de tipo / memória.)

Mas ainda há várias APIs importantes baseadas em ObjC que usam seletores, incluindo timers e o padrão target / action. O Swift fornece o tipo Selector para trabalhar com eles. (Swift usa isso automaticamente no lugar do tipo SEL da ObjC.)

No Swift 2.2 (Xcode 7.3) e posterior (incluindo Swift 3 / Xcode 8 e Swift 4 / Xcode 9):

Você pode construir um Selector partir de um tipo de função Swift usando a expressão #selector .

let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)

O melhor desta abordagem? Uma referência de função é verificada pelo compilador Swift, portanto, você pode usar a expressão #selector somente com pares de classe / método que realmente existem e são elegíveis para uso como seletores (consulte "Disponibilidade do seletor" abaixo). Você também é livre para tornar sua referência de função tão específica quanto você precisar, de acordo com as regras do Swift 2.2+ para nomeação de tipo de função .

(Isso é realmente uma melhoria em relação à diretiva @selector() do @selector() , porque a verificação do -Wundeclared-selector do compilador verifica apenas se o seletor nomeado existe. A referência da função Swift que você passa para #selector verifica a existência, a associação em uma classe e a assinatura do tipo .)

Há algumas ressalvas extras para as referências de função que você passa para a expressão #selector :

  • Múltiplas funções com o mesmo nome base podem ser diferenciadas por seus rótulos de parâmetro usando a sintaxe mencionada anteriormente para referências de função (por exemplo, insertSubview(_:at:) vs insertSubview(_:aboveSubview:) ). Mas se uma função não tiver parâmetros, a única maneira de desambiguá-la é usar uma conversão com a assinatura do tipo da função (por exemplo, foo as () -> () vs foo(_:) ).
  • Há uma sintaxe especial para pares getter / setter de propriedades no Swift 3.0+. Por exemplo, dado um var foo: Int , você pode usar #selector(getter: MyClass.foo) ou #selector(setter: MyClass.foo) .

Notas gerais:

Casos em que #selector não funciona e nomeação: Às vezes você não tem uma referência de função para fazer um seletor com (por exemplo, com métodos registrados dinamicamente no runtime ObjC). Nesse caso, você pode construir um Selector partir de uma string: por exemplo, Selector("dynamicMethod:") - embora você perca a verificação de validade do compilador. Quando você faz isso, você precisa seguir as regras de nomenclatura ObjC, incluindo dois pontos (:) para cada parâmetro.

Disponibilidade do seletor: O método referenciado pelo seletor deve ser exposto ao tempo de execução ObjC. No Swift 4, todo método exposto a ObjC deve ter sua declaração precedida pelo atributo @objc . (Nas versões anteriores, você obteve esse atributo gratuitamente em alguns casos, mas agora você precisa declará-lo explicitamente.)

Lembre-se de que private símbolos private também não estão expostos ao tempo de execução - seu método precisa ter, pelo menos, visibilidade internal .

Caminhos principais: estão relacionados, mas não exatamente, aos seletores. Há uma sintaxe especial para estes no Swift 3, por exemplo: chris.valueForKeyPath(#keyPath(Person.friends.firstName)) . Veja SE-0062 para detalhes. E ainda mais coisas sobre o KeyPath no Swift 4 , certifique-se de usar a API correta baseada em KeyPath em vez de seletores, se apropriado.

Você pode ler mais sobre seletores em Interagindo com APIs Objective-C em Usando Swift com Cocoa e Objective-C .

Nota: Antes do Swift 2.2, o Selector estava em conformidade com o StringLiteralConvertible , portanto, você pode encontrar um código antigo no qual as strings nuas são passadas para APIs que usam seletores. Você vai querer executar "Convert to Current Swift Syntax" no Xcode para obter aqueles usando #selector .


Pode ser útil observar onde você configura o controle que aciona a ação.

Por exemplo, descobri que ao configurar um UIBarButtonItem, eu tinha que criar o botão dentro de viewDidLoad ou então eu iria obter uma exceção de seletor não reconhecido.

override func viewDidLoad() {
    super.viewDidLoad() 

    // add button
    let addButton = UIBarButtonItem(image: UIImage(named: "746-plus-circle.png"), style: UIBarButtonItemStyle.Plain, target: self, action: Selector("addAction:"))
    self.navigationItem.rightBarButtonItem = addButton
}

func addAction(send: AnyObject?) {     
    NSLog("addAction")
}

Se você quiser passar um parâmetro para a função do NSTimer, então aqui está sua solução:

var somethingToPass = "It worked"

let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false)

func tester(timer: NSTimer)
{
    let theStringToPrint = timer.userInfo as String
    println(theStringToPrint)
}

Inclua os dois pontos no texto do seletor (tester :) e seu (s) parâmetro (s) vão em userInfo.

Sua função deve ter o NSTimer como parâmetro. Em seguida, basta extrair userInfo para obter o parâmetro passado.


Seletores são uma representação interna de um nome de método em Objective-C. Em Objective-C "@selector (methodName)" iria converter um método de código-fonte em um tipo de dados de SEL. Como você não pode usar a sintaxe @selector no Swift (o rickster está lá), você precisa especificar manualmente o nome do método como um objeto String diretamente, ou passando um objeto String para o tipo Seletor. Aqui está um exemplo:

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:"logout"
)

ou

var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)

Usando #selector irá verificar o seu código em tempo de compilação para se certificar de que o método que você deseja chamar realmente existe. Melhor ainda, se o método não existir, você receberá um erro de compilação: o Xcode se recusará a criar seu aplicativo, banindo assim o esquecimento de outra possível fonte de bugs.

override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.rightBarButtonItem =
            UIBarButtonItem(barButtonSystemItem: .Add, target: self,
                            action: #selector(addNewFireflyRefernce))
    }

    func addNewFireflyReference() {
        gratuitousReferences.append("Curse your sudden but inevitable betrayal!")
    }

Atualização Swift 2.2+ e Swift 3

Use a nova expressão #selector , que elimina a necessidade de usar literais de string, tornando o uso menos propenso a erros. Para referência:

Selector("keyboardDidHide:")

torna-se

#selector(keyboardDidHide(_:))

Veja também: Proposta Swift Evolution

Nota (Swift 4.0):

Se usar #selector você precisaria marcar a função como @objc

Exemplo:

@objc func something(_ sender: UIButton)


Para o Swift 3

// Código de amostra para criar temporizador

Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)

WHERE
timeInterval:- Interval in which timer should fire like 1s, 10s, 100s etc. [Its value is in secs]
target:- function which pointed to class. So here I am pointing to current class.
selector:- function that will execute when timer fires.

func updateTimer(){
    //Implemetation 
} 

repeats:- true/false specifies that timer should call again n again.

Swift 4.0

você cria o Seletor como abaixo.

1. Adicione o evento a um botão como:

button.addTarget(self, action: #selector(clickedButton(sender:)), for: UIControlEvents.touchUpInside)

e a função será como abaixo:

@objc func clickedButton(sender: AnyObject) {

}

Swift 4.1
Com uma amostra do gesto de toque

let gestureRecognizer = UITapGestureRecognizer()
self.view.addGestureRecognizer(gestureRecognizer)
gestureRecognizer.addTarget(self, action: #selector(self.dismiss(completion:)))

// Use destination 'Class Name' directly, if you selector (function) is not in same class.
//gestureRecognizer.addTarget(self, action: #selector(DestinationClass.dismiss(completion:)))


@objc func dismiss(completion: (() -> Void)?) {
      self.dismiss(animated: true, completion: completion)
}

Veja o documento da Apple para mais detalhes sobre: Expressão do Seletor


Create Refresh control using Selector method.   
    var refreshCntrl : UIRefreshControl!
    refreshCntrl = UIRefreshControl()
    refreshCntrl.tintColor = UIColor.whiteColor()
    refreshCntrl.attributedTitle = NSAttributedString(string: "Please Wait...")
    refreshCntrl.addTarget(self, action:"refreshControlValueChanged", forControlEvents: UIControlEvents.ValueChanged)
    atableView.addSubview(refreshCntrl)

// Refresh Control Method

func refreshControlValueChanged(){
    atableView.reloadData()
    refreshCntrl.endRefreshing()

}






nstimer