Si bien creo que puedo responder a su pregunta, no es una respuesta que le guste.
TL; DR: las @objc
funciones pueden no estar actualmente en extensiones de protocolo. En su lugar, podría crear una clase base, aunque esa no es una solución ideal.
Extensiones de protocolo y Objective-C
Primero, esta pregunta / respuesta ( Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c ) parece sugerir que debido a la forma en que se envían las extensiones de protocolo bajo el capó, los métodos declarados en las extensiones de protocolo no son visibles para la objc_msgSend()
función, y por lo tanto, no son visibles para el código Objective-C. Dado que el método que está tratando de definir en su extensión debe ser visible para Objective-C (así que UIKit
puede usarlo), le grita por no incluirlo @objc
, pero una vez que lo incluye, le grita porque @objc
no está permitido en extensiones de protocolo. Esto probablemente se deba a que las extensiones de protocolo actualmente no pueden ser visibles para Objective-C.
También podemos ver que el mensaje de error una vez que agregamos @objc
dice "@objc solo se puede usar con miembros de clases, protocolos @objc y extensiones concretas de clases". Esta no es una clase; una extensión de un protocolo @objc no es lo mismo que estar en la propia definición del protocolo (es decir, en los requisitos), y la palabra "concreto" sugeriría que una extensión de protocolo no cuenta como una extensión de clase concreta.
Solución alterna
Desafortunadamente, esto prácticamente le impide usar extensiones de protocolo cuando las implementaciones predeterminadas deben ser visibles para los marcos Objective-C. Al principio, pensé que tal vez @objc
no estaba permitido en su extensión de protocolo porque Swift Compiler no podía garantizar que los tipos conformes fueran clases (aunque lo haya especificado específicamente UIViewController
). Así que puse un class
requisito P1
. Esto no funcionó.
Quizás la única solución es simplemente usar una clase base en lugar de un protocolo aquí, pero obviamente esto no es completamente ideal porque una clase puede tener una sola clase base pero cumplir con múltiples protocolos.
Si elige seguir esta ruta, tenga en cuenta esta pregunta ( Método de protocolo opcional de Swift 3 ObjC no llamado en subclase ). Parece que otro problema actual en Swift 3 es que las subclases no heredan automáticamente las implementaciones de requisitos de protocolo opcionales de su superclase. La respuesta a esas preguntas utiliza una adaptación especial de @objc
para sortearla.
Informar el problema
Creo que esto ya se está discutiendo entre los que trabajan en los proyectos de código abierto de Swift, pero puede estar seguro de que lo saben utilizando el Informe de errores de Apple , que probablemente llegará al Swift Core Team, o el informador de errores de Swift . Sin embargo, cualquiera de estos puede encontrar su error demasiado amplio o ya conocido. El equipo de Swift también puede considerar lo que está buscando como una nueva función de idioma, en cuyo caso primero debe consultar las listas de correo .
Actualizar
En diciembre de 2016, se informó de este problema a la comunidad de Swift. El problema aún está marcado como abierto con una prioridad media, pero se agregó el siguiente comentario:
Esto es intencionado. No hay forma de agregar la implementación del método a cada adoptante, ya que la extensión podría agregarse después de la conformidad con el protocolo. Sin embargo, supongo que podríamos permitirlo si la extensión está en el mismo módulo que el protocolo.
Sin embargo, dado que su protocolo está en el mismo módulo que su extensión, es posible que pueda hacer esto en una versión futura de Swift.
Actualización 2
En febrero de 2017, uno de los miembros del Swift Core Team cerró oficialmente este problema como "No funciona" con el siguiente mensaje:
Esto es intencional: las extensiones de protocolo no pueden introducir puntos de entrada @objc debido a las limitaciones del tiempo de ejecución de Objective-C. Si desea agregar puntos de entrada @objc a NSObject, amplíe NSObject.
Extender NSObject
o incluso UIViewController
no logrará exactamente lo que desea, pero desafortunadamente no parece que sea posible.
En el futuro (muy) a largo plazo, es posible que podamos eliminar por @objc
completo la dependencia de los métodos, pero es probable que ese momento no llegue pronto, ya que los marcos de Cocoa no están escritos actualmente en Swift (y no pueden estarlo hasta que tenga un ABI estable) .
Actualización 3
A partir del otoño de 2019, esto se está convirtiendo en un problema menor porque cada vez se escriben más marcos de Apple en Swift. Por ejemplo, si usa en SwiftUI
lugar de UIKit
, elude el problema por completo porque @objc
nunca sería necesario al referirse a un SwiftUI
método.
Los marcos de Apple escritos en Swift incluyen:
- SwiftUI
- RealityKit
- Combinar
- CryptoKit
Uno esperaría que este patrón continúe con el tiempo ahora que Swift es oficialmente ABI y el módulo es estable a partir de Swift 5.0 y 5.1, respectivamente.
@objc