Swift使协议扩展成为通知观察者

Swi*_*ter 24 ios swift swift2 protocol-extension

我们考虑以下代码:

protocol A {
    func doA()
}

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

  func keyboardDidShow(notification: NSNotification) {

  }
}
Run Code Online (Sandbox Code Playgroud)

现在看一下实现A的UIViewController子类:

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

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

   func doA() {
   }
}
Run Code Online (Sandbox Code Playgroud)

但令人惊讶的是,这会因错误而崩溃:

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

那么我应该在视图控制器本身中实现观察者吗?不能留在延期?

以下事情已经尝试过.

制作A类协议.将keyboardDidShow添加到协议本身作为签名.

protocol A:class {
   func doA()
   func keyboardDidShow(notification: NSNotification)
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*nio 34

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

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.")
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 你如何删除观察者?假设我想要一个删除观察者的函数(也在扩展中),然后从deinit调用它 (5认同)
  • @JamesPaolantonio你能更具体地说明如何实现`unregisterForNotification`方法吗?要删除观察者,您需要存储`addObserverForName`的返回,但这在扩展名上是不可能的 (4认同)

小智 1

为了避免崩溃,请在使用该协议的 Swift 类中实现观察者方法。

\n\n

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

\n\n

\xe2\x80\x9c如果您的 Swift 类继承自 Objective-C 类,则该类中的所有方法和属性都可用作 Objective-C 选择器。\xe2\x80\x9d

\n\n

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

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