Search code examples
swiftnsnotificationcenternsnotifications

Removing NSNotificationObserver From Different ViewController


I have an observer that I register in one class as so:

class ViewControllerA: UIViewController {

//create shared class reference
var sharedClassReference_A = SharedClass()


//initialize Notification Observer and store observer reference in sharedClass
override func viewDidLoad() {
    super.viewDidLoad()

    var observerHandler: Any? = nil

    observerHandler = NotificationCenter.default.addObserver(self, selector: #selector(ViewControllerA.appDidTerminate(_:)), name: .UIApplicationWillTerminate, object: nil)

    self.sharedClassReference_A.sharedHandler = observerHandler

}

//perform some action when a notification is received
@objc func appDidTerminate(_ notification: NSNotification) {

    //perform some action

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "segueA_X" {
        let destinationController = segue.destination as! ViewControllerX
       destinationController.sharedClassReference_X = self.sharedClassReference_A
    }
}

}

I store a reference to the observer in a shared class:

class SharedClass {

var sharedHandler: Any? = nil

}

I attempt to remove the observer once I reach a different view controller as so:

class ViewControllerX: UIViewController {

var sharedClassReference_X = SharedClass()

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

    //Attempt to remove observer registered in ViewControllerA
    if let observerHandler = self.sharedClassReference_X.sharedHandler {
         NotificationCenter.default.removeObserver(observerHandler)
    }
}

}

I know that removing the observer using this approach is failing, because the observer is getting called after ViewControllerX is deallocated.

My question is: How can I successfully initialize an observer in one class (ViewControllerA) and be able to remove it later in a different class (ViewControllerX)?


Solution

  • I think it's better to follow the general guidelines of setting the observers inside viewDidLoad/viewWillAppear and removing them inside deinit / viewDidDisappear respectively according to your case , as this

    NotificationCenter.default.addObserver(self, selector: #selector(ViewControllerA.appDidTerminate(_:)), name: .UIApplicationWillTerminate, object: nil)
    

    returns void

    //

    class ViewControllerX: UIViewController { 
       var aRef:ViewControllerA!
    }
    

    in prepareForSegue

    destinationController.aRef = self
    

    Then use

    NotificationCenter.default.removeObserver(aRef, name: NSNotification.Name.UIApplicationWillTerminate, object: nil)