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.)

Sirab33
  • 1,247
  • 3
  • 12
  • 27
  • 1
    If you had used `#selector`, the compiler would've pointed out the problem – `sayHello` needs to be `@objc`. Compare https://stackoverflow.com/q/44390378/2976878 – Hamish Oct 11 '17 at 13:40
  • Use like this `#selector(yourVC.yourfunctionName)` – Mannopson Oct 11 '17 at 13:47
  • As already mentioned by @Hamish 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)` – Leo Dabus Oct 11 '17 at 13:47
  • 1
    @Mannopson no need to pass the view controller prefix. btw It should always start with an uppercase letter – Leo Dabus Oct 11 '17 at 13:49
  • @LeoDabus I always use the `self` instead of `viewControllerName`. Example: `#selector(self.functionName)` – Mannopson Oct 11 '17 at 13:54
  • self it is totally unnecessary. btw you mean ViewControllerName not its instance – Leo Dabus Oct 11 '17 at 13:59

3 Answers3

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

zekel
  • 9,227
  • 10
  • 65
  • 96
Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100
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")
}
Giang
  • 3,553
  • 30
  • 28
  • 4
    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`. – Michael Dautermann Jul 03 '18 at 05:36
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

Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52