textfielddidchange shouldchangecharactersin begin ios swift protocols uitextfielddelegate

ios - shouldchangecharactersin - textfielddidchange swift 3



swift 2.0-La extensión del protocolo UITextFieldDelegate no funciona (2)

Estoy tratando de agregar un comportamiento predeterminado en algunos métodos de UITextFieldDelegate usando extensiones de protocolo así:

extension ViewController: UITextFieldDelegate { // Works if I uncommented this so I know delegates are properly set // func textFieldShouldReturn(textField: UITextField) -> Bool { // textField.resignFirstResponder() // return true // } } extension UITextFieldDelegate { func textFieldShouldReturn(textField: UITextField) -> Bool { textField.resignFirstResponder() return true } }

Como puedes adivinar, el teclado nunca se despide. Realmente no puedo ver dónde está el problema aquí. ¿Es esta una limitación del idioma? ¿Alguien ya lo hizo con éxito?

EDITAR:

Como sugirió @Logan, la implementación del método del protocolo predeterminado no funciona con los protocolos marcados como @objc . Sin embargo, UITextFieldDelegate tiene la siguiente firma de public protocol UITextFieldDelegate : NSObjectProtocol {...}

He probado la implementación predeterminada para NSObjectProtocol y parece que funciona bien:

protocol Toto: NSObjectProtocol { func randomInt() -> Int } extension Toto { func randomInt() -> Int { return 0 } } class Tata: NSObject, Toto {} let int = Tata().randomInt() // returns 0


Buena discusión aquí, y exactamente lo que estoy sospechando en este punto también. Otra cosa que no se menciona aquí, tal vez se deba a un problema más amplio de que obj-c no puede acceder a las implementaciones de la extensión del protocolo Swift.

Por ejemplo, el siguiente código:

class MyViewController: UIViewController, MyTextFieldDelegateProtocol { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.delegate = self } } extension MyViewController: UITextFieldDelegate { func textFieldDidBeginEditing(textField: UITextField) { print("shouldChangeCharactersInRange called") } }

Generará lo siguiente en el encabezado Swift generado para la extensión:

@interface MyViewController (SWIFT_EXTENSION(MyApp)) <UITextFieldDelegate> - (void)textFieldDidBeginEditing:(UITextField * __nonnull)textField; @end

Sin embargo, utiliza las extensiones de protocolo de la siguiente manera (similar a tu publicación):

class MyViewController: UIViewController, MyTextFieldDelegateProtocol { // ... } @objc protocol MyTextFieldDelegateProtocol: UITextFieldDelegate {} extension MyTextFieldDelegateProtocol { func textFieldDidBeginEditing(textField: UITextField) { print("shouldChangeCharactersInRange called") } }

Genera lo siguiente en el encabezado Swift para el protocolo:

SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_") @protocol MyTextFieldDelegateProtocol <UITextFieldDelegate> @end

La implementación no es visible en absoluto, por lo que parece implicar que las implementaciones de extensión de protocolo no son compatibles con obj-c. También encontré a alguien que hizo esa pregunta aquí (aunque todavía no hay respuestas): ¿Se puede cambiar el método definido en extensiones en protocolos a los que se accede en Objective-c?

Desafortunadamente, todavía no he encontrado ningún documento oficial de Apple sobre esta limitación.


No puedo ser 100% positivo, pero esto es lo que creo que está sucediendo:

Las extensiones de protocolo no son accesibles desde ObjC . Dado que UITextFieldDelegate es un protocolo ObjC , depende del envío de ObjC . En lo que respecta al compilador, los métodos en su implementación por defecto son inaccesibles, aunque existan.

Para aclarar, podemos extender estos protocolos si es realmente una extensión y agrega comportamiento. Este comportamiento solo será accesible en Swift y no debería ser problemático de ninguna manera.

El problema es que las implementaciones predeterminadas no son accesibles a ObjC .

Aquí hay un ejemplo rápido de una versión personalizada:

@objc protocol Test : class { func someFunc() -> String } extension Test { func someFunc() -> String { return "" } } // Fails here ''candidate is not @objc but protocol requires it` class Hi : NSObject, Test { }

Xcode sugiere @objc pero seguirá sugiriendo esto una y otra vez hasta que obtengas @objc @objc @objc Hi : ...

Basándome en nuestra conversación a continuación, hice esto que parece estar funcionando. Todavía no puedo explicar completamente por qué:

@objc public protocol Toto: UITextFieldDelegate { optional func randomInt() -> Int } extension Toto { func randomInt() -> Int { return 0 } func textFieldShouldReturn(textField: UITextField) -> Bool { return false } } class Tata: NSObject, Toto { }

Ok, me doy cuenta de que estoy considerando un problema diferente, y mientras esto se compila, no funcionará, y el problema es el envío dinámico. Si intenta agregar su método w / @objc , o dynamic , el compilador le advertirá que no puede enviar de esta manera, excepto en las clases. Como una excepción de protocolo no se ajusta a esto, cuando ObjC envía el mensaje enviado, no puede encontrar la implementación en su extensión.

Como Swift se actualiza constantemente, aquí es cuando esta respuesta era aplicable:

Swift 2.0 Xcode 7 GM