Search code examples
iosswiftmemory-managementswift5nsnotificationcenter

How to removeObserver in Swift 5 using addObserver closure method


This is my first post. I'm Japanese iOS engineer (just became this month).

I have a trouble with removeObserver method of NotificationCenter in Swift 5.

I added observer to ViewController (VC) by using closure type addObserver. I want to remove this Observer when VC's deinitialization has called.

I wrote NotificationCenter.default.removeObserver(self) in VC's deinit method. But, this seemed not to work for me.

What's the problem???

Additionally, if my code has memory leak problem, let me know how to fix it.

Here's piece of my code.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] notification in

            guard let self = self else { return }
            self.loadWeather(notification.object)
        }
    }
    
    deinit {
        print(#function)
        print("ViewController died")

        NotificationCenter.default.removeObserver(self)
    }
}

Solution

  • Set your observer object to current view controller.

    From apple doc.s, object is

    The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer.

    NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification,
                                           object: self,
                                           queue: nil) { [weak self] notification in
        guard let self = self else { return }
        self.loadWeather(notification.object)
    }
    

    Removing observer from NotificationCenter

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    

    ANOTHER WAY

    You can also make copy of Notification Observer object and remove it from NotificationCenter in deinit.

    let notificationCenter = NotificationCenter.default
    var loadWeatherObserver: NSObjectProtocol?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        loadWeatherObserver = notificationCenter.addObserver(forName: UIApplication.didBecomeActiveNotification,
                                                             object: nil,
                                                             queue: nil) { [weak self] notification in
            guard let self = self else { return }
            self.loadWeather(notification.object)
        }
    }
    
    deinit {
        if (loadWeatherObserver != nil) {
            notificationCenter.removeObserver(loadWeatherObserver!)
        }
    }