Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS unable to remove Notification observer. Deinit not getting called

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

like image 349
Sohil Pandya Avatar asked May 12 '17 11:05

Sohil Pandya


2 Answers

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.

like image 122
adamfowlerphoto Avatar answered Sep 20 '22 00:09

adamfowlerphoto


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)
like image 31
Khalid Afridi Avatar answered Sep 23 '22 00:09

Khalid Afridi