1

I am trying to prevent a push notification show on the app home screen when a certain userMessagesViewController is currently open. I don't want users receiving a push notification if this specific viewController is open. My function that sends the push notification is in the appDelegate. How can I check. Here is my implementation so far.

  let messagesVC = UserMessageViewController()

    if messagesVC.view.window != nil {
        print("Messages viewcontroller is visible and open")
        } else {
        print("Messages viewcontroller isnt visible and not open")
    }
mandem112
  • 181
  • 14
  • Is [this](https://stackoverflow.com/questions/22882078/how-to-get-visible-viewcontroller-from-app-delegate-when-using-storyboard) related? – Ahmad F Nov 07 '18 at 15:32
  • Just an option to consider, if you don’t want to extend UIApplication, is to create a singleton property that the messages controller toggles whenever it comes into and out of view. The messages controller could also post a notification whenever it comes into and out of view that the app delegate can listen for. The app delegate can check this property to determine if it should or shouldn’t post. Just options to consider. – trndjc Nov 07 '18 at 16:13

2 Answers2

2

By initiating messagesVC, you're creating a brand new UserMessageViewController that won't have been presented yet. The particular instance of the controller you want will already be instantiated, so you must find it using the view controller hierarchy.

The AppDelegate gives you access to the rootViewController of your application which will be the very first controller you have in your storyboard. From this controller, you can make your way through the child view controllers in search of a UserMessageViewController.

Here is an extension that will start at the rootViewController and bubble its way up until it reaches the top of the view controller hierarchy stack.

extension UIApplication {
    func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        switch (base) {
        case let controller as UINavigationController:
            return topViewController(controller.visibleViewController)
        case let controller as UITabBarController:
            return controller.selectedViewController.flatMap { topViewController($0) } ?? base
        default:
            return base?.presentedViewController.flatMap { topViewController($0) } ?? base
        }
    }
}

Create a new file called UIApplication+TopViewController.swift and paste in the above extension. Then inside AppDelegate, you will be able to get the current view controller that is being presented using UIApplication.shared.topViewController():

if let messagesVC = UIApplication.shared.topViewController() as? UserMessageViewController {
    print("Messages viewcontroller is visible and open")
} else {
    print("Messages viewcontroller isnt visible and not open")
}

By casting the top view controller to UserMessageViewController, we can determine whether or not the notification should be presented.

Callam
  • 11,409
  • 2
  • 34
  • 32
0

This should work for you:

if messagesVC.viewIfLoaded?.window != nil {
    // viewController is visible, handle notification silently.
}

Your appDelegate will have a reference to the VC. It should probably be a property of the delegate.

Woodstock
  • 22,184
  • 15
  • 80
  • 118