Ios Swift使协议扩展成为通知观察员 让我们考虑下面的代码: protocol A { func doA() } extension A { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { } }

Ios Swift使协议扩展成为通知观察员 让我们考虑下面的代码: protocol A { func doA() } extension A { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { } },ios,swift,swift2,protocol-extension,Ios,Swift,Swift2,Protocol Extension,现在来看一个UIViewController子类,它实现了: class AController: UIViewController, A { override func viewDidLoad() { super.viewDidLoad() self.registerForNotification() triggerKeyboard() } func triggerKeyboard() { // Some code that

现在来看一个UIViewController子类,它实现了:

class AController: UIViewController, A {
   override func viewDidLoad() {
      super.viewDidLoad()
      self.registerForNotification()
      triggerKeyboard()
   }

   func triggerKeyboard() {
      // Some code that make key board appear
   }

   func doA() {
   }
}
但令人惊讶的是,这会因为一个错误而崩溃:

keyboardDidShow::发送到实例的选择器无法识别 0x7fc97adc3c60

那么我应该在视图控制器本身中实现观察器吗?它不能留在分机里吗

下面的事情已经尝试过了

制作一个类协议。 将keyboardDidShow作为签名添加到协议本身

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

为了避免崩溃,在使用协议的Swift类中实现observer方法

实现必须在Swift类本身中,而不仅仅是协议扩展,因为选择器总是引用Objective-C方法,协议扩展中的函数不能用作Objective-C选择器。但是,如果Swift类继承自Objective-C类,则Swift类中的方法可用作Objective-C选择器

另外,在Xcode 7.1中,
self
addObserver
调用中将其指定为观察者时,必须向下转换为
AnyObject

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")
    }
}

通过实现
NSNotificationCenter
的较新的
-addObserverForName:object:queue:usingBlock:
方法并直接调用该方法,我解决了类似的问题

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.")
    }
}

此示例将导致在协议扩展中调用
keyboardDidShow

在Swift中使用选择器要求您的具体类必须从NSObject继承。要在协议扩展中强制执行此操作,应使用
where
。例如:

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) {

  }
}

除了詹姆斯·保兰托尼奥的回答。可以使用关联对象实现
unregisterForNotification
方法

var指针:UInt8=0
扩展NSObject{
var userInfo:[字符串:任意]{
得到{
如果让userInfo=objc_getAssociatedObject(self,&指针)作为?[字符串:Any]{
返回用户信息
}
self.userInfo=[String:Any]()
返回self.userInfo
}
设置(新值){
objc_setAssociatedObject(self、指针、newValue、.objc_ASSOCIATION_RETAIN)
}
}
}
协议A{}
扩展名A,其中Self:UIViewController{
var默认值:NotificationCenter{
得到{
return NotificationCenter.default
}
}
func键盘显示(通知:通知){
//键盘确实显示了
}
func registerForNotification(){
userInfo[“didShowObserver”]=默认值。addObserver(forName:.UIKeyboardDidShow,对象:nil,队列:nil,使用:keyboardDidShow)
}
func unregisterForNotification(){
如果让didShowObserver=userInfo[“didShowObserver”]作为NSObjectProtocol{
默认值。removeObserver(didShowObserver,名称:.UIKeyboardDidShow,对象:nil)
}
}
}

我使用
NSObjectProtocol
解决了它,如下所示

@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)
}
}

我过去也尝试过类似的方法,但我发现Swift的协议扩展不能与Objective-C协议和类一起工作,我很困惑
扩展A{}
???您正在谈论的是
扩展控制器{}
您只需要将参数添加到方法或从选择器的name@MidhunMP . 是的,它是
扩展名A{}
。Swift 2以后的新功能。这就是所谓的协议扩展。它甚至可以为协议方法添加默认功能。该方法是
func keyboardDidShow(通知:NSNotification)
,它与
选择器(“keyboardDidShow:”)
非常明显,但没有想到它-cudos!伟大的发现!错过了那一个:)你如何移除观察者?假设我想要一个函数来移除观察器(在扩展中也是如此),然后从deinit@tolkiana您还可以添加一个
func unregisterForNotification()
@JamesPaolantonio您可以更具体地说明如何实现
unregisterForNotification
方法吗?要删除观察者,您需要存储
addObserverForName
的返回值,但这在扩展上是不可能的