Estoy intentando crear una NSTimer
en Swift
pero estoy teniendo algunos problemas.
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
es una función en la misma clase.
Me sale un error en el editor:
No se pudo encontrar una sobrecarga para 'init' que acepte los argumentos proporcionados
Cuando cambio selector: test()
a selector: nil
el error desaparece.
He intentado:
selector: test()
selector: test
selector: Selector(test())
Pero nada funciona y no puedo encontrar una solución en las referencias.
selector: test()
llamaríatest
y pasaría su valor de retorno alselector
argumento.Respuestas:
Swift en sí no usa selectores: varios patrones de diseño que en Objective-C hacen uso de selectores funcionan de manera diferente en Swift. (Por ejemplo, el uso opcional en el encadenamiento de los tipos de protocolos o
is
/as
pruebas en lugar derespondsToSelector:
, y cierres de uso siempre que sea posible en lugar deperformSelector:
para un mejor tipo / seguridad de la memoria).Pero todavía hay una serie de API importantes basadas en ObjC que usan selectores, incluidos los temporizadores y el patrón de objetivo / acción. Swift proporciona el
Selector
tipo para trabajar con estos. (Swift usa esto automáticamente en lugar delSEL
tipo de ObjC ).En Swift 2.2 (Xcode 7.3) y versiones posteriores (incluidos Swift 3 / Xcode 8 y Swift 4 / Xcode 9):
Puede construir un
Selector
tipo de función Swift utilizando la#selector
expresión.¿Lo bueno de este enfoque? El compilador Swift verifica una referencia de función, por lo que puede usar la
#selector
expresión solo con pares de clase / método que realmente existen y son elegibles para usar como selectores (consulte "Disponibilidad de selectores" a continuación). También es libre de hacer que su referencia de función sea tan específica como lo necesite, según las reglas de Swift 2.2+ para nombres de tipo de función .(Esto es realmente una mejora con respecto a la
@selector()
directiva de ObjC , porque la-Wundeclared-selector
verificación del compilador solo verifica que el selector con nombre existe. La referencia de la función Swift que pasa a la#selector
existencia de cheques, membresía en una clase y firma de tipo).Hay un par de advertencias adicionales para las referencias de funciones que pasa a la
#selector
expresión:insertSubview(_:at:)
vsinsertSubview(_:aboveSubview:)
). Pero si una función no tiene parámetros, la única forma de desambiguarla es usar unaas
conversión con la firma de tipo de la función (por ejemplo,foo as () -> ()
vsfoo(_:)
).var foo: Int
, puede usar#selector(getter: MyClass.foo)
o#selector(setter: MyClass.foo)
.Notas generales:
Casos en los
#selector
que no funciona y nombres: a veces no tiene una referencia de función para hacer un selector (por ejemplo, con métodos registrados dinámicamente en el tiempo de ejecución de ObjC). En ese caso, puede construir un aSelector
partir de una cadena: por ejemploSelector("dynamicMethod:")
, aunque pierde la comprobación de validez del compilador. Cuando haga eso, debe seguir las reglas de nomenclatura de ObjC, incluidos los dos puntos (:
) para cada parámetro.Disponibilidad del selector: el método al que hace referencia el selector debe estar expuesto al tiempo de ejecución ObjC. En Swift 4, cada método expuesto a ObjC debe tener su declaración precedida por el
@objc
atributo. (En versiones anteriores obtuviste ese atributo gratis en algunos casos, pero ahora tienes que declararlo explícitamente).Recuerde que los
private
símbolos tampoco están expuestos al tiempo de ejecución: su método debe tener al menosinternal
visibilidad.Rutas clave: están relacionadas pero no son exactamente iguales a los selectores. También hay una sintaxis especial para estos en Swift 3: por ejemplo
chris.valueForKeyPath(#keyPath(Person.friends.firstName))
. Ver SE-0062 para más detalles. Y aún másKeyPath
cosas en Swift 4 , así que asegúrate de estar usando la API correcta basada en KeyPath en lugar de selectores si es apropiado.Puede leer más sobre los selectores en Interactuar con las API de Objective-C en Uso de Swift con Cocoa y Objective-C .
Nota: Antes de Swift 2.2,
Selector
conforme aStringLiteralConvertible
, por lo que puede encontrar código antiguo donde se pasan cadenas desnudas a las API que toman selectores. Deberá ejecutar "Convertir a sintaxis Swift actual" en Xcode para que los usen#selector
.fuente
size:andShape:
, si se nombra el primer argumento puede necesitar unWith
, es decir,initWithData:
parafunc init(Data data: NSData)
Aquí hay un ejemplo rápido sobre cómo usar la
Selector
clase en Swift:Tenga en cuenta que si el método pasado como una cadena no funciona, fallará en tiempo de ejecución, no en tiempo de compilación, y bloqueará su aplicación. Ten cuidado
fuente
@selector
es útil, pero no se aplica tan formalmente como podría pensar. El "selector no declarado" es simplemente una advertencia del compilador, porque siempre se pueden introducir nuevos selectores en tiempo de ejecución. Sin embargo, las referencias de selector verificables / refactorables en Swift serían una buena solicitud de función .Además, si su clase (Swift) no desciende de una clase Objective-C, entonces debe tener dos puntos al final de la cadena de nombre del método de destino y debe usar la propiedad @objc con su método de destino, por ejemplo
de lo contrario, recibirá un error "Selector no reconocido" en tiempo de ejecución.
fuente
Selector
palabra clave no es obligatoria. Entonces, en este caso, la firma debe ser@objc func method(timer: NSTimer) {/*code*/}
@objc
trabajó para mi. No necesitaba incluirtimer: NSTimer
en mi firma de método para que se llamara.Swift 2.2+ y Swift 3 Update
Use la nueva
#selector
expresión, que elimina la necesidad de usar literales de cadena haciendo que el uso sea menos propenso a errores. Para referencia:se convierte
Ver también: Propuesta de evolución rápida
Nota (Swift 4.0):
Si lo usa
#selector
, deberá marcar la función como@objc
Ejemplo:
@objc func something(_ sender: UIButton)
fuente
Swift 4.0
creas el Selector como a continuación.
1.Agregue el evento a un botón como:
y la función será la siguiente:
fuente
@objc
antes de lofunc
que se requiere en Swift 4.Para los futuros lectores, descubrí que tuve un problema y recibí un
unrecognised selector sent to instance
error causado al marcar el objetivofunc
como privado.El
func
DEBE ser visible públicamente para ser llamado por un objeto con referencia a un selector.fuente
objc
antes de su declaración Ej:@objc private func foo() { ...
entonces puedes usar"foo"
como selector todo lo que quierasinternal
, por lo tanto, no especifica ningún modificador de acceso. A menudo uso este patrón://MARK: - Selector Methods\n extension MyController {\n func buttonPressed(_ button: UIButton) {
En caso de que alguien más tenga el mismo problema que tuve con NSTimer donde ninguna de las otras respuestas solucionó el problema, es realmente importante mencionar que, si está utilizando una clase que no hereda de NSObject, ya sea directamente o en lo profundo de la jerarquía ( por ejemplo, archivos rápidos creados manualmente), ninguna de las otras respuestas funcionará incluso cuando se especifica de la siguiente manera:
Sin cambiar nada más que hacer que la clase herede de NSObject, dejé de recibir el error "Selector no reconocido" y conseguí que mi lógica funcionara como se esperaba.
fuente
Si desea pasar un parámetro a la función desde el NSTimer, aquí está su solución:
Incluya los dos puntos en el texto del selector (probador :), y sus parámetros irán en userInfo.
Su función debe tomar NSTimer como parámetro. Luego solo extraiga userInfo para obtener el parámetro que pasó.
fuente
scheduledTimerWith...
automáticamente lo agrega al runloop actual, por lo que no hay ningún comportamiento extraño aquí;)Los selectores son una representación interna de un nombre de método en Objective-C. En Objective-C, "@selector (methodName)" convertiría un método de código fuente en un tipo de datos de SEL. Como no puede usar la sintaxis @selector en Swift (el rickster está en el punto allí), debe especificar manualmente el nombre del método como un objeto String directamente, o pasando un objeto String al tipo Selector. Aquí hay un ejemplo:
o
fuente
Swift 4.1
Con muestra de gesto de toque
Consulte el documento de Apple para obtener más detalles sobre: Expresión de selector
fuente
fuente
// Actualizar método de control
fuente
Dado que se publica Swift 3.0, es incluso un poco más sutil declarar un objetivo Acción apropiada
fuente
Cuando usas
performSelector()
/addtarget()/NStimer.scheduledTimerWithInterval()
métodos su método (que coincida con el selector) debe marcarse comoPara Swift 2.2, debe escribir '#selector ()' en lugar de la cadena y el nombre del selector para que las posibilidades de error de ortografía y bloqueo debido a eso ya no estén allí. A continuación se muestra un ejemplo
fuente
creas el Selector como a continuación.
1)
2)
Tenga en cuenta que la sintaxis @selector desapareció y se reemplazó con una cadena simple que nombra el método a llamar. Hay un área donde todos podemos estar de acuerdo en que la verbosidad se interpuso en el camino. Por supuesto, si declaramos que hay un método de destino llamado flatButtonPressed: mejor escribimos uno:
configurar el temporizador:
Para completar, aquí está el flatButtonPressed
fuente
Encontré muchas de estas respuestas útiles, pero no estaba claro cómo hacer esto con algo que no era un botón. Estaba agregando un reconocedor de gestos a un UILabel rápidamente y luché, así que esto es lo que encontré que me funcionó después de leer todo lo anterior:
Donde el "Selector" fue declarado como:
Tenga en cuenta que es público y que no estoy usando la sintaxis Selector (), pero también es posible hacerlo.
fuente
El uso de #selector verificará su código en tiempo de compilación para asegurarse de que el método al que desea llamar realmente exista. Aún mejor, si el método no existe, obtendrá un error de compilación: Xcode se negará a construir su aplicación, por lo que se olvidará de otra posible fuente de errores.
fuente
Puede ser útil tener en cuenta dónde configura el control que activa la acción.
Por ejemplo, descubrí que al configurar un UIBarButtonItem, tenía que crear el botón dentro de viewDidLoad o de lo contrario obtendría una excepción de selector no reconocida.
fuente
selector
es una palabra delObjective-C
mundo y puedes usarlaSwift
para tener la posibilidad de llamarObjective-C
desdeSwift
Te permite ejecutar algún código en tiempo de ejecuciónAntes de
Swift 2.2
la sintaxis es:Dado que el nombre de una función se pasa
Selector
comoString
parámetro ("foo") no es posible verificar un nombre en tiempo de compilación . Como resultado, puede obtener un error de tiempo de ejecución:Después de
Swift 2.2+
la sintaxis es:El autocompletado de Xcode lo ayuda a llamar al método correcto
fuente
Cambie como una simple cadena de nombres en el método que llama a la sintaxis del selector
Después de eso, escriba func test ().
fuente
Para Swift 3
// Código de muestra para crear temporizador
fuente
Selector en Swift 4:
fuente
Para Swift 3
Declaración de función en la misma clase:
fuente
self
en el selector. Esto debería ser suficiente:let timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(test), userInfo: nil, repeats: true)