0

How do you add an observer in Swift to the notification center?

do it like this:

override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(ReloadData), name: NSNotification.Name(rawValue: "ReloadData"), object: nil)

}
@objc func ReloadData(notification: NSNotification) {
        // func
        print ("FUNC TEST")
    }

But every time the controller closes/opens (switch between the tabs of the tabbar), a new listener is added. And when I call

print ("Call Notif")
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ReloadData"), object: nil)

"func ReloadData" is called several times. Console:

Call Notif
FUNC TEST
FUNC TEST

will switch between the tabs of the tabbar again.

Call Notif
FUNC TEST
FUNC TEST
FUNC TEST

How can I oblige you only once ?

Sergo
  • 111
  • 2
  • 10
  • unsubscribe in your `viewWillDisappear` method via `NotificationCenter.default.removeObserver(self)` and subscribe in `viewWillAppear`. [This is actually a duplicate question](https://stackoverflow.com/a/51745479/1040347) – Aleksey Potapov Feb 25 '20 at 15:59
  • 1
    Does this answer your question? [Swift NotificationCenter remove observer quickest way](https://stackoverflow.com/questions/51745194/swift-notificationcenter-remove-observer-quickest-way) – Aleksey Potapov Feb 25 '20 at 16:00
  • Aleksey, YES! But I need the observer to stay. I don't want it removed. I want it in a single copy. – Sergo Feb 25 '20 at 16:08
  • 1
    Although above comment resolves visible part of your problem, the real problem is that **you have multiple instances of that controller loaded in memory**. So you should see why that happens. That's a sure memory leak / bad design. – timbre timbre Feb 25 '20 at 16:15
  • Do you subscribe on notification in your viewControllers' superclass? Because UITableViewController's controllers are created just once (viewDidLoad is called once - on creation) and are being deallocated when their parent (tabbarcontroller) is deallocated. – Aleksey Potapov Feb 25 '20 at 16:15
  • I call in viewDidLoad() in UITableViewController. – Sergo Feb 25 '20 at 16:20
  • if no answer, I will get back to this later. Curious. And, if you don't mind, provide some additional info regarding of how you fill your views into tabbarcontroller. – Aleksey Potapov Feb 25 '20 at 16:54

2 Answers2

0

I have a similar situation as yours. Having read https://stackoverflow.com/a/60399071/14414215 and https://stackoverflow.com/a/51745479/1040347 and trying it out, it didn't work for me in my particular scenario whereby I am using a UITabBarController design to pass data to to different tabs.

Tab1 is the main screen Tab2 is the library of workouts (user to select the data)

Then using the TabBarController as the intermediate https://stackoverflow.com/a/65499693/14414215 to pass data from Tab2 to Tab1. When adding the removeObserver in Tab1

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self)
}

This will result in Data not getting passed from Tab2 to Tab1 as the notification was unsubscribed whenever user moves from Tab1 to Tab2.

I also tried to add the removeObserver into the TabBarController but this didn't do anything.

In the end, what worked was to unsubscribe from within the objc eg:

in Tab1:

override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(ReloadData), name: NSNotification.Name(rawValue: "ReloadData"), object: nil)

}
@objc func ReloadData(notification: NSNotification) {
        // func
        print ("FUNC TEST")
        NotificationCenter.default.removeObserver(self). // Adding it here works and its then only called ONCE
    }
app4g
  • 670
  • 4
  • 24
-1

Like it or not, the simplest solution for that is to make use of the controller's life cycle.

  1. Subscribe to notification for each appearance or load of the controller.
  2. Remove notification for every deinit or disappearance of the controller.

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ReloadData"), object: nil)
    
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        NotificationCenter.default.removeObserver(self)
    }
    

If you have a base class for each and every controllers of yours, you can put the removeObserver() in that base class.

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95