Estou tentando criar um NSTimer
arquivo, Swift
mas estou tendo alguns problemas.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
é uma função na mesma classe.
Eu recebo um erro no editor:
Não foi possível encontrar uma sobrecarga para 'init' que aceita os argumentos fornecidos
Quando eu mudo 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.
selector: test()
chamariatest
e passaria seu valor de retorno aoselector
argumento.Respostas:
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 derespondsToSelector:
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 doSEL
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ãoA 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:insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Mas se uma função não possui parâmetros, a única maneira de desambiguar é usar umaas
conversão com a assinatura de tipo da função (por exemplo,foo as () -> ()
vsfoo(_:)
).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 aSelector
partir de uma string: por exemploSelector("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 menosinternal
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 maisKeyPath
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 comStringLiteralConvertible
, 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
.fonte
size:andShape:
With
initWithData:
func init(Data data: NSData)
Aqui está um exemplo rápido de como usar a
Selector
classe no Swift:Observe que, se o método passado como uma string não funcionar, ele falhará no tempo de execução, não no tempo de compilação e travará o aplicativo. Seja cuidadoso
fonte
@selector
é útil, mas não é aplicado de maneira tão formal quanto você imagina. "Seletor não declarado" é apenas um aviso do compilador, porque novos seletores sempre podem ser introduzidos em tempo de execução. Porém, referências ao seletor verificáveis / refatoráveis no Swift seriam uma boa solicitação de recurso .Além disso, se sua classe (Swift) não descender de uma classe Objective-C, você deverá ter dois pontos no final da cadeia de nome do método de destino e deverá usar a propriedade @objc com seu método de destino, por exemplo
caso contrário, você receberá um erro "Seletor não reconhecido" em tempo de execução.
fonte
Selector
palavra-chave não é obrigatória. Portanto, neste caso, a assinatura deve ser@objc func method(timer: NSTimer) {/*code*/}
@objc
trabalhou para mim. Não precisei incluirtimer: NSTimer
na minha assinatura de método para que ela fosse chamada.Atualização Swift 2.2+ e Swift 3
Use a nova
#selector
expressão, que elimina a necessidade de usar literais de string, tornando o uso menos propenso a erros. Para referência:torna-se
Veja também: Proposta de evolução rápida
Nota (Swift 4.0):
Se estiver usando,
#selector
você precisará marcar a função como@objc
Exemplo:
@objc func something(_ sender: UIButton)
fonte
Swift 4.0
você cria o seletor como abaixo.
1. adicione o evento a um botão como:
e a função será como abaixo:
fonte
@objc
antes defunc
que é exigido em Swift 4.Para futuros leitores, descobri que estava com um problema e estava recebendo um
unrecognised selector sent to instance
erro causado pela marcação do destinofunc
como privado.O
func
DEVE estar publicamente visível para ser chamado por um objeto com uma referência a um seletor.fonte
objc
lo antes da declaração. Ex:@objc private func foo() { ...
então você pode usar"foo"
como um seletor tanto você gostainternal
, portanto, não especificando nenhum modificador de acesso. Costumo usar este padrão://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: UIButton) {
Caso outra pessoa tenha o mesmo problema que eu 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 herda do NSObject, direta ou profundamente na hierarquia ( por exemplo, arquivos rápidos criados manualmente), nenhuma das outras respostas funcionará mesmo quando especificada da seguinte forma:
Sem alterar nada além de apenas herdar a classe do NSObject, parei de receber o erro "Seletor não reconhecido" e fiz com que minha lógica funcionasse conforme o esperado.
fonte
Se você deseja passar um parâmetro para a função do NSTimer, aqui está sua solução:
Inclua os dois pontos no texto do seletor (testador :) e seus parâmetros vão em userInfo.
Sua função deve usar o NSTimer como parâmetro. Em seguida, basta extrair userInfo para obter o parâmetro que passou.
fonte
scheduledTimerWith...
automaticamente adiciona à RunLoop atual - portanto, não há comportamento estranho aqui em tudo;)Seletores são uma representação interna de um nome de método em Objective-C. No Objective-C, "@selector (methodName)" converteria um método de código-fonte em um tipo de dados SEL. Como você não pode usar a sintaxe @selector no Swift (o rickster está no ponto), você deve especificar manualmente o nome do método como um objeto String diretamente ou passando um objeto String para o tipo Selector. Aqui está um exemplo:
ou
fonte
Swift 4.1
Com amostra de gesto de toque
Consulte o documento da Apple para obter mais detalhes sobre: Expressão do seletor
fonte
fonte
// Atualizar método de controle
fonte
Como o Swift 3.0 é publicado, é ainda mais sutil declarar uma targetAction apropriada
fonte
Ao usar
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
métodos, seu método (correspondente ao seletor) deve ser marcado comoPara o Swift 2.2, você precisa escrever '#selector ()' em vez do nome da string e do seletor, para que as possibilidades de erro ortográfico e falha devido a isso não existam mais. Abaixo está um exemplo
fonte
você cria o seletor como abaixo.
1
2)
Observe que a sintaxe @selector desapareceu e foi substituída por uma String simples, nomeando o método a ser chamado. Há uma área em que todos podemos concordar que a verbosidade atrapalhou. Obviamente, se declaramos que existe um método de destino chamado flatButtonPressed: é melhor escrevermos um:
ajuste o temporizador:
Para ser completo, aqui está o flatButtonPressed
fonte
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 com dificuldades, então aqui está o que eu achei que funcionou para mim depois de ler tudo acima:
Onde o "Seletor" foi declarado como:
Observe que é público e que eu não estou usando a sintaxe Selector (), mas também é possível fazer isso.
fonte
O uso de #selector verificará seu código no momento da compilação para garantir que o método que você deseja chamar realmente exista. 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 erros.
fonte
Pode ser útil observar onde você configura o controle que aciona a ação.
Por exemplo, descobri que, ao configurar um UIBarButtonItem, tive que criar o botão no viewDidLoad, caso contrário, obteria uma exceção de seletor não reconhecida.
fonte
Altere como uma nomeação simples de string no método que chama a sintaxe do seletor
Depois disso, digite func test ().
fonte
selector
é uma palavra deObjective-C
mundo e você é capaz de usá-lo deSwift
ter a possibilidade de chamadaObjective-C
a partirSwift
Ele permite que você execute algum código em tempo de execuçãoAntes
Swift 2.2
da sintaxe:Como um nome de função é passado
Selector
como um parâmetro String ("foo"), não é possível verificar um nome em tempo de compilação . Como resultado, você pode receber um erro de tempo de execução:Depois que
Swift 2.2+
a sintaxe é:O preenchimento automático do Xcode ajuda você a chamar o método certo
fonte
Para Swift 3
// Exemplo de código para criar timer
fonte
Seletor no Swift 4:
fonte
Para rápido 3
Declaração de função Na mesma classe:
fonte
self
no seletor. Isso deve ser suficiente:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)