You could also utilise the NotificationCenter to achieve a loosely coupled way to "request a view controller"; if you will.
For example, create a custom UINavigationController that observes for the custom Notification and upon receiving one, looks for the requested UIViewController and pops back to it.
class MyNavigationController : UINavigationController {
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(forName: NSNotification.Name("RequestViewController"), object: nil, queue: OperationQueue.main) { [unowned self] (note) in
            guard let targetType = note.object as? UIViewController.Type else {
                print("Please provide the type of the VC to display as an `object` for the notification")
                return
            }
            // Find the first VC of the requested type
            if let targetVC = self.viewControllers.first(where: { $0.isMember(of: targetType) }) {
                self.popToViewController(targetVC, animated: true)
            }
            else {
                // do what needs to be done? Maybe instantiate a new object and push it?
            }
        }
    }
}
Then in the object you want to go back to a specific ViewController, post the notification.
@IBAction func showViewController(_ sender: Any) {
    NotificationCenter.default.post(Notification(name: NSNotification.Name("RequestViewController"), object: ViewController2.self))
}
Now, it's also fairly easy to adopt this method for other presentation-styles.
Instead of using the NotificationCenter, you could also muster up a Mediator to achieve the loose coupling.