How to call additional function using Selector and NotificationCenter
Language : Swift 3
IDE : XCode 8.3.2 (8E2002)
I have a protocol with an optional function foo
@objc protocol SomeProtocol {
@objc optional func foo(_ notification: Notification)
}
extension SomeProtocol {
func listenToFoo() {
NotificationCenter.default.addObserver(self, selector: #selector(self.foo(_:)), name: NSNotification.Name(rawValue: "UltimateNotificationKeyLOL"), object: nil)
}
}
If I extend this code to a class , say a UIViewController
.
class CrashingViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.listenToFoo()
}
}
extension CrashingViewController: SomeProtocol { }
Now there is a problem as it foo
is an optional function, if someone posts Notification
with a key the NSNotification.Name(rawValue: "UltimateNotificationKeyLOL")
app will crash because I haven't implemented yet foo
. So the above code will fail in this case.
However, if I do this
class GodzillaViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.listenToFoo()
}
}
extension GodzillaViewController: SomeProtocol {
func foo(_ notification: Notification) {
print("lol")
}
}
No fault is thrown as it is foo(_:)
no longer optional.
Also : this code is not possible#selector(self.foo?(_:))
Question . Is it possible for the selector to call an additional function without crashing the application?
source to share
If I, wherever you are, would make a quick protocol like this:
// Protocol declaration
protocol SomeProtocol {
func foo(_ notification: Notification)
}
// Provide default implementation for optional methods of SomeProtocol
extension SomeProtocol {
func foo(_ notification: Notification) {}
}
// Extend SomeProtocol with additional methods
extension SomeProtocol {
func listenToFoo() {
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "UltimateNotificationKeyLOL"), object: nil, queue: nil) { (notification) in
self.foo(notification)
}
}
}
As you can see, doing this has several advantages:
- You only have Swift code (no @objc)
- By adding a standard implementation
foo
, you've made the function optional. - Your notification can still be triggered
foo
without crashing as it will execute if needed in the default implementation - You can even add code to the default method if you still want to do something!
UPDATE
You can see in the function listenToFoo()
that I have used another function addObserver
that uses closure instead, the reason is that #selector still requires the function to be exposed by @objc and the closure is not done:
func addObserver (for name name: NSNotification.Name ?, object obj: Any ?, queue: OperationQueue ?, using block: @escaping (Notification) → Void) → NSObjectProtocol
source to share