Swift 4 - Notification Center addObserver issue
Asked Answered
W

3

14

I'm crashing and getting an unrecognized selector error every time a Notification arrives and the App tries to execute its associated method. Here's my code - which is in viewDidLoad:

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: Selector(("sayHello")), name:NSNotification.Name(rawValue: "dataDownloadCompleted"), object: nil)

The sayHello() method is quite simple - looks like this:

func sayHello() {
    print("Hello")
}

I've verified that the Notification is posted successfully and that it arrives successfully - so that's not the issue. The crash happens when the App looks to act upon the arrival of the Notification - by executing the sayHello() method. It keeps giving me that unrecognized selector error.

Any ideas what I'm doing wrong? (By the way, this worked perfectly with Swift 3 & Xcode 8, but now with Swift 4 and Xcode 9 the syntax has changed [Xcode walked me through the necessary code fixes/updates] - but the crashes keep happening.)

Weimer answered 11/10, 2017 at 13:38 Comment(6)
If you had used #selector, the compiler would've pointed out the problem – sayHello needs to be @objc. Compare https://mcmap.net/q/23779/-how-can-i-deal-with-objc-inference-deprecation-with-selector-in-swift-4/2976878Tenderhearted
Use like this #selector(yourVC.yourfunctionName)Phoneme
As already mentioned by @Tenderhearted you should use #selector(sayHello) and your method signature you should also pass the notification object (drop the NS prefix) @objc func sayHello(_ notification: Notification)Samsun
@Phoneme no need to pass the view controller prefix. btw It should always start with an uppercase letterSamsun
@LeoDabus I always use the self instead of viewControllerName. Example: #selector(self.functionName)Phoneme
self it is totally unnecessary. btw you mean ViewControllerName not its instanceSamsun
C
33

You can improve your code with these steps:

extension Notification.Name {
    static let dataDownloadCompleted = Notification.Name(
       rawValue: "dataDownloadCompleted")
}

And use it like this:

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
                               selector: #selector(YourClass.sayHello),
                               name: .dataDownloadCompleted,
                               object: nil)

But as was already pointed out, issue is solved by changing to #selector

Counterintelligence answered 11/10, 2017 at 13:52 Comment(1)
Name is not member of Notification - issue is coming in swift 4Joab
S
10
Data Receiving - Add observer:

override func viewDidLoad() {
     super.viewDidLoad()
     NotificationCenter.default.addObserver(self, selector: #selector(yourfunction(notfication:)), name: .postNotifi, object: nil)
}

@objc func yourfunction(notfication: NSNotification) {
     print("xxx")
}

Sending Data - Post Notification:

override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      NotificationCenter.default.removeObserver(self, name: .postNotifi, object: nil)
}

extension Notification.Name {
      static let postNotifi = Notification.Name("postNotifi")
}
Sapowith answered 12/3, 2018 at 6:30 Comment(1)
if you do your code this way, the observer is removed when the view disappears (e.g. when another view is pushed onto navigation stack), but if that new view is popped back to the original view (where the observer used to live), there's no notification observer. Better to put addObserver in viewWillAppear.Arvad
C
8

Swift 4.0 & Xcode 9.0+:

Send(Post) Notification:

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)

OR

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil, userInfo: ["Renish":"Dadhaniya"])

Receive(Get) Notification:

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Function-Method handler for received Notification:


@objc func methodOfReceivedNotification(notification: Notification) {}

Swift 3.0 & Xcode 8.0+:

Send(Post) Notification:


NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil)

Receive(Get) Notification:


NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Method handler for received Notification:

func methodOfReceivedNotification(notification: Notification) {
  // Take Action on Notification
}

Remove Notification:

deinit {
  NotificationCenter.default.removeObserver(self, name: Notification.Name("NotificationIdentifier"), object: nil)
}

Swift 2.3 & Xcode 7:

Send(Post) Notification

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

Receive(Get) Notification


NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)

Method handler for received Notification

func methodOfReceivedNotification(notification: NSNotification){
  // Take Action on Notification
}

Ref:https://medium.com/@javedmultani16/notification-in-swift-4-8b0db631f49d

Castlereagh answered 24/8, 2019 at 22:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.