For doing dependency injection properly, you need 2 things :
1 - inject the data in your root view controller.
This can be done in the App delegate as shown in MarMass answer, or if you need something that also suits document applications, you can do it as I suggested in the accepted answer there : Can't use storyboard custom instantiated window controller
2 - you need to pass data from the root view controller to its descendants.
You will find many people saying "use prepareForSegue" for that. I really dislike using prepeareForSegue because it creates a hard dependency from the root view controller to its descendants, when I think each view controller should be kept independent.
You can't reuse your controllers in another Storyboard flow without modifying the view controller code (in that case prepareForSegue) again and again.
Plus, if you have many relationship, your prepareForSegue methods become a huge "case" code. Always an indicator that we can do better.
I suggest another method :
Create an extension to your view controller with an @IBSegueAction, and hook that @IBSegueAction to the segue view Interface Builder. This works both for transition segues and embedding segue.
extension FatherViewController {
@IBSegueAction func injectToTextViewController(_ coder: NSCoder) -> NSViewController? {
// Create the destination view controller
let destinationViewController = TextViewController(coder: coder)!
// Compute here the data to inject to the destination controller. As this is an extension of the father view controller, you have access to all its data
destinationViewModel.data = self.data
return destinationViewController
}
}

(don't forget the ':' at the end of the selector name)
This way, you can keep your view controller code completely clean of thecontroller-to-controller relationships.
I like to keep all my segues actions in a single file that I put in the same directory as my storyboard. If I change the storyboard, I change the segue actions, not the controllers...
