1

I'm struggling with a case to use Cocoa Bindings between view controllers in separate files. I've checked some links for inspiration but still not there. I figured it's better to post a question and rest my mind a bit...

Similar topics: Binding selection across multiple view controllers in a single window interface

Sharing an NSArrayController between multiple views in separate NIB files

I have one main controller MainViewController.m/.h/.xib with two custom views.

There's also a separate view controller SecondViewController.m/.h/.xib. Its xib contain a table view basically, together with an ArrayController which is bound to the table view's column. This works fine with bindings and selection etc.

Now back in my main controller, I'd like to access the selection index from SecondViewController for the table view.

My attempt thus far

  1. In my main XIB, I created a ViewController in IB and set custom class and nib file to SecondViewController.

  2. Created an ArrayController in SecondViewController's XIB, whose contentArray is set to the KVC list property 'lists'. This displays the content correctly in the table view, as mentioned above.

    Q: how do I setup bindings in my MainViewController in such a way that I can access the object selected in SecondViewController? Because I want to draw the details for that object as subviews from my main view controller. Kind of a master-detail interface described in the Cocoa Tutorials.

Community
  • 1
  • 1
H.Rabiee
  • 4,747
  • 3
  • 23
  • 35
  • Create a secondVC outlet in MainVC that points to the SecondVC instance. Have a tableView outlet in SecondVC that points to the table view in the SecondVC. In MainVC, use a keypath of secondVC.tableView.selectionIndex... right? That's pretty vanilla stuff, so I'm wondering if you are looking to do something more complex. – stevesliva Oct 30 '14 at 18:04
  • hm perhaps it's easy. So you mean that I need a tableview outlet in secondVC in order to expose it later in my mainvc? btw there's no selectionIndex, only selectedRowIndexes - that's what you mean? – H.Rabiee Oct 31 '14 at 08:13
  • Yeah, semantics. But as long as your MainVC does a little work to track the secondVC instance (avoiding a nil pointer) I don't see why you can't bind through the hierarchical keypath. – stevesliva Oct 31 '14 at 15:56
  • @stevesliva I tried this in a sandbox project, one array controller in the mainVC and second array controller connected through outlets. All I get is a left parenthesis in the table view row for the array controller that is connected through outlet (from second vc). The main array controller is fine. – H.Rabiee Nov 02 '14 at 16:52
  • I don't think you should be binding or observing ``selectedRowIndexes`` - this is an ``NSTableView`` property. Probably, you should set up, and watch for, changes to the *Selection Indexes* binding of the ``NSArrayController`` providing the content for your second table view (see my answer below). – Paul Patterson Nov 03 '14 at 11:08

1 Answers1

1

If you want to use Key-Value Observing to make your MainViewController aware of changes to the selected row in the table managed by your SecondViewController, I think the best way to do it is to set a value for the NSArrayController binding Selection Indexes (this is the array controller providing the content for your second table view).

In your SecondViewController class files add a property like this:

@property (nonatomic, copy) NSIndexSet *secondTableSelectedIndexes;

Now select the relevent green NSArrayController cube in SecondViewController.xib, navigate to it's bindings inspector and set the Selection Indexes binding to reference the index-set property you just created. This is a read-write binding. You will probably never write it yourself in code (though you can if you want), but each time you select a new row in your SecondViewController-managed table this index set will be updated automatically, thus, it is this property that you will observe.

To set up the observer, wherever you have access to both view controllers, add the following:

/* Have my main view controller watch for selection changes in my 
 * second view controller's table
 */

self.secondViewController = [[SecondTableViewController alloc] initWithNibName:@"SecondTableViewController" bundle:nil];

[self.secondViewController addObserver:self.mainViewController
       forKeyPath:@"secondTableselectedIndexes"
          options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionPrior
          context:nil];

Changes to secondTableSelectedIndexes can then be picked up by implementing -observeValueForKeyPath:ofObject:change:context: in MainViewController.

Paul Patterson
  • 6,840
  • 3
  • 42
  • 56
  • ok I'll try that for the selection indexes. But the problem of getting the correct string into the table view remains, still the "(" is displayed – H.Rabiee Nov 03 '14 at 13:17
  • Which table view? You have a table view in your ``SecondTableViewController`` xib, is there also one in ``MainViewController``? If you want your ``MainViewController`` to be kept abreast of the selection in the second view controller there is no need to mess about with the selection indexes. Once you've clarified the number of table views, I can explain the bindings. – Paul Patterson Nov 03 '14 at 16:03
  • I've tried this in a sandbox project with simple a array of strings. In my mainvc I have two array controllers, and one table view with two columns. The first column is bound to mainarraycontroller.arrangedObjects. The second column is bound to secondarraycontroller.arrangedObjects. SecondArrayController's contentArray is bound to self.secondViewController.tableArray (secondViewController is an IBOutlet property). First column is fine, second column displays "(". – H.Rabiee Nov 03 '14 at 17:39
  • It's not all that uncommon to see one array controller provide the data for two tables, but I've not come across using two array controllers to provide the content for one table. I'm not sure how this should work, and I'm tempted to say you should probably rethink - though I appreciate it may be perfectly possible to get it working. I can't help any further with this particular set-up. – Paul Patterson Nov 03 '14 at 18:05
  • ok the sole purpose of two array controllers was to facilitate debugging, I guess I was overthinking it. If I disabled the binding for the first column it worked fine with displaying the content from the second view controller. Thanks! Accepting your answer as well since I can now observe the selectionIndexes in my main vc. Next step is to act on the selection! – H.Rabiee Nov 03 '14 at 22:47
  • I noticed if I implement didChangeValueForKey in my second view controller, it gets called but it's not propagated to the observeValueForKeyPath in the main VC. Why is that? It's as if I cannot listen for the key in two places. – H.Rabiee Nov 05 '14 at 22:45