what protocol extensions extension example delegate are apple and ios swift swift2 protocol-extension

ios - extensions - swift protocol and delegate example



Swift hace que la extensión de protocolo sea un observador de notificación (5)

Además de la respuesta de James Paolantonio. Un método unregisterForNotification se puede implementar utilizando objetos asociados.

var pointer: UInt8 = 0 extension NSObject { var userInfo: [String: Any] { get { if let userInfo = objc_getAssociatedObject(self, &pointer) as? [String: Any] { return userInfo } self.userInfo = [String: Any]() return self.userInfo } set(newValue) { objc_setAssociatedObject(self, &pointer, newValue, .OBJC_ASSOCIATION_RETAIN) } } } protocol A {} extension A where Self: UIViewController { var defaults: NotificationCenter { get { return NotificationCenter.default } } func keyboardDidShow(notification: Notification) { // Keyboard did show } func registerForNotification() { userInfo["didShowObserver"] = defaults.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil, using: keyboardDidShow) } func unregisterForNotification() { if let didShowObserver = userInfo["didShowObserver"] as? NSObjectProtocol { defaults.removeObserver(didShowObserver, name: .UIKeyboardDidShow, object: nil) } } }

Consideremos el siguiente código:

protocol A { func doA() } extension A { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { } }

Ahora mira una subclase UIViewController que implementa A:

class AController: UIViewController, A { override func viewDidLoad() { super.viewDidLoad() self.registerForNotification() triggerKeyboard() } func triggerKeyboard() { // Some code that make key board appear } func doA() { } }

Pero sorprendentemente esto falla con un error:

keyboardDidShow:]: selector no reconocido enviado a la instancia 0x7fc97adc3c60

Entonces, ¿debería implementar el observador en el controlador de vista en sí? ¿No puede quedarse en la extensión?

Siguiendo cosas ya probadas.

haciendo que A sea un protocolo de clase. Añadiendo keyboardDidShow al protocolo en sí mismo como firma.

protocol A:class { func doA() func keyboardDidShow(notification: NSNotification) }


El uso de selectores en Swift requiere que su clase concreta debe heredar de NSObject. Para aplicar esto en una extensión de protocolo, debe usar where . Por ejemplo:

protocol A { func doA() } extension A where Self: NSObject { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { } }


Lo resolví usando NSObjectProtocol como abajo,

@objc protocol KeyboardNotificaitonDelegate: NSObjectProtocol { func keyboardWillBeShown(notification: NSNotification) func keyboardWillBeHidden(notification: NSNotification) } extension KeyboardNotificaitonDelegate { func registerForKeyboardNotifications() { //Adding notifies on keyboard appearing NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func deregisterFromKeyboardNotifications() { //Removing notifies on keyboard appearing NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) } }


Para evitar el bloqueo, implemente el método del observador en la clase Swift que usa el protocolo.

La implementación debe estar en la clase Swift en sí, no solo en la extensión de protocolo, porque un selector siempre se refiere a un método Objective-C, y una función dentro de una extensión de protocolo no está disponible como un selector Objective-C. Sin embargo, los métodos de una clase Swift están disponibles como selectores Objective-C si la clase Swift hereda de una clase Objective-C

"Si su clase Swift hereda de una clase Objective-C, todos los métodos y propiedades de la clase están disponibles como selectores Objective-C".

Además, en Xcode 7.1, el self tiene que ser AnyObject a AnyObject cuando se lo especifica como el observador en la llamada addObserver .

protocol A { func doA() } extension A { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self as! AnyObject, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { print("will not appear") } } class ViewController: UIViewController, A { override func viewDidLoad() { super.viewDidLoad() self.registerForNotification() triggerKeyboard() } func triggerKeyboard(){ // Some code that makes the keyboard appear } func doA(){ } func keyboardDidShow(notification: NSNotification) { print("got the notification in the class") } }


- addObserverForName:object:queue:usingBlock: un problema similar implementando el - addObserverForName:object:queue:usingBlock: más nuevo - addObserverForName:object:queue:usingBlock: de NSNotificationCenter y llamando directamente al método.

extension A where Self: UIViewController { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidShowNotification, object: nil, queue: nil) { [unowned self] notification in self.keyboardDidShow(notification) } } func keyboardDidShow(notification: NSNotification) { print("This will get called in protocol extension.") } }

Este ejemplo provocará que se llame a keyboardDidShow en la extensión de protocolo.