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?

+3


source to share


1 answer


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

+4


source







All Articles