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 de respondsToSelector:
, y cierres de uso siempre que sea posible en lugar de performSelector:
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 del SEL
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.
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)
¿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:
- Las funciones múltiples con el mismo nombre base se pueden diferenciar por sus etiquetas de parámetros utilizando la sintaxis mencionada anteriormente para las referencias de funciones (por ejemplo,
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
). Pero si una función no tiene parámetros, la única forma de desambiguarla es usar una as
conversión con la firma de tipo de la función (por ejemplo, foo as () -> ()
vs foo(_:)
).
- Hay una sintaxis especial para los pares getter / setter de propiedad en Swift 3.0+. Por ejemplo, dado a
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 a Selector
partir de una cadena: por ejemplo Selector("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 menos internal
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ás KeyPath
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 a StringLiteralConvertible
, 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
.
selector: test()
llamaríatest
y pasaría su valor de retorno alselector
argumento.