iOS unable to remove Notification observer. Deinit not getting called
Asked Answered
O

3

8

I have a UIView similar to the one you can see below:

class ViewTaskViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
    super.viewDidLoad()
    subscribeToNotifications()
}

func subscribeToNotifications() {
    let notification = NotificationCenter.default
    notification.addObserver(forName: Notification.Name(rawValue: "TimerUpdated"), object: nil, queue: nil, using: handleUpdateTimer)
    print("Subscribed to NotificationCenter in ViewTaskViewController")
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    print("TUFU TUFU TUFU")
    NotificationCenter.default.removeObserver(self)
}

deinit {
    print("DENINT")
}

@objc func handleUpdateTimer(notification: Notification) {
    if let userInfo = notification.userInfo, let timeInSeconds = userInfo["timeInSeconds"] as? Int {

        withUnsafePointer(to: &self.view) {
            print("We got timeeeeee \(timeInSeconds) \($0)")
        }

       //do something here....
    }
}

}

The issue I am having is that I am unable to remove the observers from this particular UIView when the user hits the back button and returns to another viewController.

ViewWillDisppear is called but deinit is not called. The strange thing is that if we remove subscribeToNotifications() from viewDidLoad() then the deinit is called.

The other issue is related to a memory leak. As you can see in the screenshot below, when the view does subscribe to notifications and the user leaves/re-enters the view, the memory usage increase. enter image description here

Now compare that to when the subscribeToNotifications() is commented out, there is no increase in memory usage and only one instance of the viewController. enter image description here The conclusion is that there seems to be a correlation between the notification subscription creation of a new instance of the UIView hence the deinit is not being called.

I'd like to find out if there is a way we can deinitialize the view and unsubscribe from the notification.

Please let me know if you need further information. :)

Ominous answered 12/5, 2017 at 11:5 Comment(1)
Documentation for the addObserver method you're using says, "To unregister observations, you pass the object returned by this method to removeObserver(_:)." Instead, you seem to be assuming that self is the registered object.Disjunction
B
5

I've found the removeObserver() only works if you use this version of addObserver()

notification.addObserver(self, selector:#selector(self.handleUpdateTimer), name: Notification.Name(rawValue: "TimerUpdated"), object: nil)

I'm guessing with the original version you aren't actually indicating who the observer is.

Bruise answered 12/5, 2017 at 12:49 Comment(1)
Thank you very much for this! I had already tried what Khalid had suggested but still wasn't getting it remove the observer. But your method certainly helps and solves the issue! :)Ominous
M
2

As @Spads said you can use

NotificationCenter.default.addObserver(self, selector: #selector(subscribeToNotifications), name: NSNotification.Name(rawValue: "TimerUpdate"), object: nil)

or the one you already have. you can remove your notification by it's name or it's reference

NotificationCenter.default.removeObserver(self, name: "TimerUpdate", object: nil)

if you declared your notification at the top of your class then you can directly pass the reference of your notification to be removed in your case notification

 NotificationCenter.default.removeObserver(notification)
Milline answered 12/5, 2017 at 13:58 Comment(1)
So I did try that even before submitting this question and didn't get it to work, although the other method of adding observer seems to have done the trick! :) ThanksOminous
S
0

You should store your newly added observer in a opaque object (NSObjectProtocol) and then call NotificationCenter.default.removeObserver(self.nameOfObserver)

Sevilla answered 7/5, 2019 at 12:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.