0

I have two ViewControllers (ViewController is the first; SecondViewController is the second) embedded in a Navigation Controller.

On ViewController, there is a NotificationCenter observer in viewDidLoad.

On SecondViewController, I have a button that should post a notification to ViewController that will trigger a UIAlertController when it appears again.

ViewController:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addObservers()
    }

    func addObservers(){
        NotificationCenter.default.addObserver(self, selector: #selector(alertThankYou), name: Notification.Name(rawValue: Constants.handleThankYouNotif), object: nil)
    }
    func removeObservers(){
        NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: Constants.handleThankYouNotif), object: nil)
    }

    @objc func alertThankYou(notification: Notification) {
        self.view.backgroundColor = .red
        let alertController = UIAlertController(title: "THANK YOU", message: "lorem ipsum dolor sit amet.", preferredStyle: .alert)
        let okAction = UIAlertAction(title: "Done", style: UIAlertAction.Style.default) { (result : UIAlertAction) -> Void in
            print("done pressed")
        }
        alertController.addAction(okAction)
        self.present(alertController, animated: true, completion: nil)
    }

    deinit {
        removeObservers()
    }

}

SecondViewController:

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // Press this first to post the Notification!
    @IBAction func TRIGGERPOSTPRESSED(_ sender: UIButton) {
        NotificationCenter.default.post(name: Notification.Name(Constants.handleThankYouNotif), object: nil)
    }

    // Then press this to return back to ViewController to HOPEFULLY see an Alert.
    @IBAction func close(_ sender: Any) {
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.window?.rootViewController?.dismiss(animated: true, completion: nil)
            (appDelegate.window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: false)
        }
    }

}

The problem: On SecondViewController, when TRIGGERPOSTPRESSED is pressed, I get this warning in console:

Warning: Attempt to present UIAlertController on ViewController whose view is not in the window hierarchy!

What should happen: On SecondViewController, when TRIGGERPOSTPRESSED is pressed, I should not get any errors. Then when close is pressed and the App returns back to ViewController, i should get the alert!

How can I achieve this with NotificationCenter?

Joe
  • 3,772
  • 3
  • 33
  • 64

2 Answers2

0

I Think you should not use NotificationCenter, in this case, you should use Delegates Protocol Pattern as in this previous question about Notification Center vs. Delegation in iOS SDK and of course this not the issue producer but it's the right practice to use Delegation when you need only tow classes to communicate.

Mohamed Shaban
  • 2,263
  • 1
  • 15
  • 23
  • It has to be NotificationCenter. The example I posted is minified; there will be more than 2 VC's communicating. But once I solve the issue presented in my question, I will be able to solve the rest. – Joe Feb 05 '19 at 20:51
  • @Joe can't agree with you that it has to be `NotificationCenter`. In most cases (and it looks that here as well), it's an anti-pattern and would bring troubles sooner or later. A lot of articles around describing consequences and possible alternatives. – Tomasz Pe Feb 05 '19 at 21:55
0

Please post the notification on completion while dismissing the SecondViewController. The code snippet:

@IBAction func close(_ sender: Any) {
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.window?.rootViewController?.dismiss(animated: true, completion: {
            NotificationCenter.default.post(name: Notification.Name(handleThankYouNotif), object: nil)
        })
        (appDelegate.window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: false)
    }
}

The alert pop up

  • While the alert does show, console reports this: `Unbalanced calls to begin/end appearance transitions for SecondViewController` – Joe Feb 05 '19 at 21:19
  • dismiss with animated: false. I hope you are not presenting secondViewController from viewDidLoad() of firstViewController. – Deblina Das Feb 05 '19 at 21:31