Let's consider the following code:
protocol A {
func doA()
}
extension A {
func registerForNotification() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil)
}
func keyboardDidShow(notification: NSNotification) {
}
}
Now look at a UIViewController subclass that implements A:
class AController: UIViewController, A {
override func viewDidLoad() {
super.viewDidLoad()
self.registerForNotification()
triggerKeyboard()
}
func triggerKeyboard() {
// Some code that make key board appear
}
func doA() {
}
}
But surprisingly this crashes with an error:
keyboardDidShow:]: unrecognized selector sent to instance 0x7fc97adc3c60
So should I implement the observer in the view controller itself? Can't it stay in the extension?
Following things already tried.
making A a class protocol. Adding keyboardDidShow to protocol itself as signature.
protocol A:class {
func doA()
func keyboardDidShow(notification: NSNotification)
}
Using selectors in Swift requires that your concrete class must inherit from NSObject. To enforce this in a protocol extension, you should use
where
. For example:I solved it using
NSObjectProtocol
as below,I solved a similar problem by implementing the newer
- addObserverForName:object:queue:usingBlock:
method ofNSNotificationCenter
and calling the method directly.This example will cause
keyboardDidShow
to be called in the protocol extension.To avoid the crash, implement the observer method in the Swift class that uses the protocol.
The implementation has to be in the Swift class itself, not just the protocol extension, because a selector always refers to an Objective-C method, and a function within a protocol extension is not available as an Objective-C selector. Yet methods from a Swift class are available as Objective-C selectors if the Swift class inherits from an Objective-C class
“If your Swift class inherits from an Objective-C class, all of the methods and properties in the class are available as Objective-C selectors.”
Also, in Xcode 7.1,
self
has to be downcast toAnyObject
when specifying it as the observer in theaddObserver
call.In addition to James Paolantonio's answer. A
unregisterForNotification
method can be implemented using associated objects.