0

I'm working on a macOS project where I have a split view containing 2 other ViewControllers and I can't figure out how to access the ViewControllers from my primary window's ViewController.

this is the setup:

screenshot of storyboard

Basically what I'm trying to do is use the Button in my ViewController on the top-left to access the Label in my SectionController on the right, which is embedded in my split view.

Since I can't create an IBAction or IBOutlet for a control in a different ViewController, I can't figure out how to get these to be connected. My current workaround has been to have a property on my AppDelegate and then access the main shared application delegate, but that feels hacky and won't scale. I'm completely lost as to how to proceed. I'm ok with using a function to pass data or whatever to the other ViewController(s).

I'm using Swift 4 with Xcode 9 (beta).

Any ideas?

Spike Grobstein
  • 532
  • 5
  • 12
  • "Since I can't create an IBAction or IBOutlet for a control in a different ViewController" Create a view controller subclass for each split. If you work for Apple, Inc. then why don't you ask your colleague? – El Tomato Sep 03 '17 at 21:41
  • each split already has a ViewController subclass and that's where I'm adding some functions/actions/properties, but have no way to reach that from my top-level view. Is there something else I'm missing? Re apple: it's a large company, I don't have any devs that work in xcode/swift/cocoa in my division. – Spike Grobstein Sep 03 '17 at 22:24

1 Answers1

1

Of course you can't create IBAction or IBOutlet for a control in a different ViewController!! But simply each view controller in the hierarchy has a reference for its child view controllers.

Method 1:

@IBAction func buttonTapped(_ sender: Any) {
    let splitViewController = self.childViewControllers[0] as! YourSplitViewController
    let targetViewController = splitViewController.childViewControllers[0] as! YourTargetViewController
    targetViewController.label.text = "Whatever!"
}

Method 2:

It may be better if you took a reference for each child controller in your "prepare for segue" method

ContainerViewController:

var mySplitViewController: YourSplitViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "splitViewSegue" {
        self.mySplitViewController = segue.destination as! YourSplitViewController
    }
}

YourSplitViewController:

var aViewController: YourFirstViewController?
var bViewController: YourSecondViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "aViewSegue" {
        self.aViewController = segue.destination as! YourFirstViewController
    } else if segue.identifier == "bViewSegue" {
        self.bViewController = segue.destination as! YourSecondViewController
    }
}

So you can access it like that in your container view controller:

@IBAction func buttonTapped(_ sender: Any) {
    self.mySplitViewController.firstViewController.label.text = "Whatever!"
}
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • do I need to subclass the NSSplitViewController in order to do this? I was noticing that I because the split view was embedded in a Container View that it wasn't visible as a `childViewController` from my top-level view and it wasn't visible as a `parent` from the bottom views. I think there's something minor that I'm missing with how I'm wiring this up. – Spike Grobstein Sep 03 '17 at 22:21
  • ok, fiddling with the info you gave me, I think I figured out what's going on (I never dealt with segues before). I'll dabble, but this has put me on the right track. Thanks! – Spike Grobstein Sep 03 '17 at 22:43
  • for method 1 you don't have to subclass UISplitViewController, You can just call it through childViewControllers property – Mohamed Elsayeh Sep 03 '17 at 22:46
  • You can just reach what you want with this short way: let splitViewController = self.childViewControllers[0] as! UISplitViewController; let targetViewController = splitViewController.childViewControllers[0] as! YourTargetViewController; targetViewController.label.text = "Whatever!"; – Mohamed Elsayeh Sep 03 '17 at 22:48
  • this worked! thanks! I'm trying to understand why it doesn't work unless I create a subclass of `NSSplitViewController`. I literally put no code in the subclass and this works, if I don't subclass it, I get nothing from `.childViewControllers`. But it works, so I'm not complaining. – Spike Grobstein Sep 05 '17 at 15:35