Estoy tratando de convertir el código fuente de mi proyecto de Swift 3 a Swift 4. Una advertencia que me da Xcode es sobre mis selectores.
Por ejemplo, agrego un objetivo a un botón usando un selector regular como este:
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
Esta es la advertencia que muestra:
El argumento de '#selector' se refiere al método de instancia 'myAction ()' en 'ViewController' que depende de la inferencia de atributo '@objc' en desuso en Swift 4
Agregue '@objc' para exponer este método de instancia a Objective-C
Ahora, presionar Fix
el mensaje de error hace esto a mi función:
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
Realmente no quiero cambiar el nombre de todas mis funciones para incluir la @objc
marca y supongo que no es necesario.
¿Cómo reescribo el selector para lidiar con la desaprobación?
Pregunta relacionada:
@objc
es necesario para exponerlos a Obj-C y, por lo tanto, usarlos con selectores.@objc
? Eso es un poco molesto, pero generalmente hago que estas funciones sean privadas, lo que requiere que lo marque como de@objc
todos modos.@objcMembers
para exponer a todos los miembros compatibles con Obj-C a Obj-C, pero no lo recomendaría a menos que realmente necesite que toda su clase esté expuesta.Respuestas:
La solución es correcta: no hay nada sobre el selector que pueda cambiar para que el método al que hace referencia esté expuesto a Objective-C.
Toda la razón de esta advertencia en primer lugar es el resultado de SE-0160 . Antes de Swift 4, se dedujo que los
internal
miembros compatibles de Objective-C de lasNSObject
clases heredadas eran@objc
y, por lo tanto, se exponían a Objective-C, lo que permitía que se los llamara utilizando selectores (ya que se requiere el tiempo de ejecución Obj-C para buscar el método implementación para un selector dado).Sin embargo, en Swift 4, este ya no es el caso. Ahora solo se infiere que las declaraciones muy específicas son
@objc
, por ejemplo, anulaciones de@objc
métodos, implementaciones de@objc
requisitos de protocolo y declaraciones con atributos que implican@objc
, como@IBOutlet
.La motivación detrás de esto, como se detalla en la propuesta vinculada anterior , es en primer lugar evitar que las sobrecargas de métodos en las
NSObject
clases heredadas choquen entre sí debido a que tienen selectores idénticos. En segundo lugar, ayuda a reducir el tamaño binario al no tener que generar thunks para los miembros que no necesitan estar expuestos a Obj-C, y en tercer lugar mejora la velocidad de la vinculación dinámica.Si desea exponer a un miembro a Obj-C, debe marcarlo como
@objc
, por ejemplo:(el migrador debe hacer esto automáticamente por usted con selectores cuando se ejecuta con la opción "minimizar inferencia" seleccionada)
Para exponer un grupo de miembros a Obj-C, puede usar un
@objc extension
:Esto expondrá todos los miembros definidos en él a Obj-C, y dará un error en cualquier miembro que no pueda ser expuesto a Obj-C (a menos que esté marcado explícitamente como
@nonobjc
).Si tiene una clase donde necesita que todos los miembros compatibles con Obj-C estén expuestos a Obj-C, puede marcar la clase como
@objcMembers
:Ahora, todos los miembros que se pueden inferir
@objc
serán. Sin embargo, no recomendaría hacer esto a menos que realmente necesite que todos los miembros estén expuestos a Obj-C, dadas las desventajas mencionadas anteriormente de tener miembros expuestos innecesariamente.fuente
@IBAction
también son automáticos@objc
? ese no era el caso hasta ahora, pero sería lógico. EDITAR: nvm, la propuesta establece claramente que@IBAction
es suficiente para que un método sea@objc
.Como documentación oficial de Apple . necesitas usar @objc para llamar a tu Método Selector.
fuente
A partir de, creo Swift 4.2, todo lo que necesitas hacer es asignar @IBAction a tu método y puedes evitar esta tonta anotación @objc
`` `
fuente
Como ya se mencionó en otras respuestas, no hay forma de evitar la
@objc
anotación para los selectores.Pero la advertencia mencionada en el OP se puede silenciar siguiendo los siguientes pasos:
Off
a continuación se muestra la captura de pantalla que ilustra los pasos mencionados anteriormente:
Espero que esto ayude
fuente
Si necesita miembros objetivos c en su controlador de vista, simplemente agregue @objcMembers en la parte superior del controlador de vista. Y puede evitar esto agregando IBAction en su código.
Asegúrese de conectar esta salida en el guión gráfico.
fuente