medium - swift protocol and delegate example
El método no ''@ objc'' no cumple el requisito opcional del protocolo ''@objc'' (1)
Si bien creo que puedo responder a su pregunta, no es una respuesta que le guste.
TL; DR:
@objc
funciones
@objc
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 (
¿Puede el método Swift definido en extensiones en protocolos
a los que se
objc_msgSend()
en 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 extensiones de protocolo no son visibles para
objc_msgSend()
función, y por lo tanto no son visibles para el código Objective-C.
Dado que el método que está intentando definir en su extensión debe ser visible para Objective-C (para que
UIKit
pueda usarlo), le grita por no incluir
@objc
, pero una vez que lo incluye, le grita porque
@objc
no está permitido en extensiones de protocolo.
Esto probablemente se deba a que actualmente las extensiones de protocolo 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".
Esto no es una clase;
una extensión a un protocolo @objc no es lo mismo que estar en la definición del protocolo en sí (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 alternativa
Desafortunadamente, esto evita por completo el uso de extensiones de protocolo cuando las implementaciones predeterminadas deben ser visibles para los marcos de 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 haya especificado específicamente
UIViewController
).
Así que puse un requisito de
class
en
P1
.
Esto no funcionó.
Quizás la única solución es simplemente usar una clase base en lugar de un protocolo aquí, pero esto obviamente no es completamente ideal porque una clase solo 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 ObjC Swift 3 no llamado en la 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
@objc
.
Informar el problema
Creo que esto ya se está discutiendo entre quienes trabajan en los proyectos de código abierto de Swift, pero puede estar seguro de que lo saben ya sea utilizando el Bug Reporter de Apple , que probablemente llegaría al equipo central de Swift o al reportero 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, este problema se informó a la comunidad Swift. El problema todavía está marcado como abierto con una prioridad media, pero se agregó el siguiente comentario:
Esto está destinado. 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 hacerlo en una versión futura de Swift.
Actualización 2
En febrero de 2017, uno de los miembros del equipo Swift Core cerró oficialmente este tema como "No lo haré" con el siguiente mensaje:
Esto es intencional: las extensiones de protocolo no pueden introducir puntos de entrada @objc debido a limitaciones del tiempo de ejecución de Objective-C. Si desea agregar puntos de entrada @objc a NSObject, extienda 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
dependencia de los métodos
@objc
, pero es probable que ese momento no llegue pronto, ya que los marcos de Cocoa no están escritos actualmente en Swift (y no puede serlo hasta que tenga una estabilidad) ABI).
Visión general:
- Tengo un protocolo P1 que proporciona una implementación predeterminada de una de las funciones opcionales de Objective-C.
- Cuando proporciono una implementación predeterminada de la función opcional, aparece una advertencia
Advertencia del compilador:
Non-''@objc'' method ''presentationController(_:viewControllerForAdaptivePresentationStyle:)'' does not satisfy optional requirement of ''@objc'' protocol ''UIAdaptivePresentationControllerDelegate''
Versión:
- Rápido: 3
- Xcode: 8 (lanzamiento público)
Intentos realizados:
-
@objc
agregar@objc
pero no ayuda
Pregunta:
- ¿Cómo resuelvo esto?
- ¿Hay alguna solución?
Código:
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
}