O Swift em si não usa seletores - vários padrões de design que no Objective-C utilizam seletores 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 fechamentos sempre que puder, em vez deperformSelector:
obter uma melhor segurança de tipo / memória.)
Mas ainda existem várias APIs importantes baseadas em ObjC que usam seletores, incluindo temporizadores e o padrão de destino / ação. Swift fornece o Selector
tipo para trabalhar com eles. (O Swift usa isso automaticamente no lugar do SEL
tipo da ObjC .)
No Swift 2.2 (Xcode 7.3) e posterior (incluindo Swift 3 / Xcode 8 e Swift 4 / Xcode 9):
Você pode construir a Selector
partir de um tipo de função Swift usando a #selector
expressão
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)
A melhor coisa dessa abordagem? Uma referência de função é verificada pelo compilador Swift, para que você possa usar a #selector
expressão apenas 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 pode fazer sua referência de função apenas tão específica quanto necessário, conforme as regras do Swift 2.2+ para nomeação de tipo de função .
(Na verdade, isso é uma melhoria em relação à @selector()
diretiva da ObjC , porque a -Wundeclared-selector
verificação 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, associação a uma classe e assinatura de tipo.)
Existem algumas advertências extras para as referências de função que você passa para a #selector
expressão:
- Várias funções com o mesmo nome de base podem ser diferenciadas por seus rótulos de parâmetro, usando a sintaxe mencionada acima para referências de função (por exemplo,
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
). Mas se uma função não possui parâmetros, a única maneira de desambiguar é usar uma as
conversão com a assinatura de tipo da função (por exemplo, foo as () -> ()
vs foo(_:)
).
- Há uma sintaxe especial para os pares getter / setter de propriedades no Swift 3.0+. Por exemplo, dado a
var foo: Int
, você pode usar #selector(getter: MyClass.foo)
ou #selector(setter: MyClass.foo)
.
Notas gerais:
Casos em #selector
que não funciona e nomeação: Às vezes você não tem uma referência de função para fazer um seletor (por exemplo, com métodos registrados dinamicamente no tempo de execução ObjC). Nesse caso, você pode construir a Selector
partir de uma string: por exemplo Selector("dynamicMethod:")
- embora você perca a verificação de validade do compilador. Ao fazer isso, você precisa seguir as regras de nomenclatura do 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 do ObjC. No Swift 4, todo método exposto ao ObjC deve ter sua declaração precedida pelo @objc
atributo (Nas versões anteriores, você obtinha esse atributo gratuitamente em alguns casos, mas agora precisa declará-lo explicitamente.)
Lembre-se de que os private
símbolos também não estão expostos ao tempo de execução - seu método precisa ter pelo menos internal
visibilidade.
Caminhos principais: estão relacionados, mas não são exatamente os mesmos, dos seletores. Também existe uma sintaxe especial no Swift 3: por exemplo chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Veja SE-0062 para detalhes. E ainda mais KeyPath
coisas no Swift 4 , verifique se você está usando a API correta baseada em KeyPath em vez de seletores, se apropriado.
Você pode ler mais sobre seletores em Interagindo com APIs do Objective-C em Usando Swift with Cocoa e Objective-C .
Nota: Antes do Swift 2.2, em Selector
conformidade com StringLiteralConvertible
, para que você possa encontrar o código antigo em que cadeias simples são passadas para APIs que usam seletores. Você deseja executar "Converter para a sintaxe Swift atual" no Xcode para obter os que estão usando #selector
.
selector: test()
chamariatest
e passaria seu valor de retorno aoselector
argumento.