0

Working on a Preference Pane. I've got an NSTabView; tabs are created dynamically from a XIB. They're all very similar, but not identical. So, I need some values to change (and some controls to appear or disappear) according to which tab is currently selected.

Normally one would think it would be possible to bind to NSTabView.selectedTabViewItem; but this does not work. Why? The value is never updated.

Then I got more creative and thought of making a computed property that returns the appropriate value for the binding to observe. Still no dice. The bindings get evaluated when the app is started and never get updated.

Then I decided to go messy and made a delegate to implement the tabView's didSelect method, whereby the currently selected tab is written to a stored property that the binding can observe.

This last approach works, but it feels very clunky and dirty. Does anyone know a better way?

Edit: I'm attempting to implement the NSTabViewController but I just can't get it to work!

If I manually bind the NSTabViewController to the NSTabView object I made in IB, everything appears to be initialized properly, but the tabs never show up. And, if I try to initialize everything in the controller, and then assign the NSTabView via the NSTabViewController.tabView property, I get

A TabView managed by a TabViewController cannot have its delegate modified

Which is odd, because I am trying to do it the way the do cumentation specifies. In fact, even if I try to do TabViewController.tabView = NSTabView() I get the same error. Is this a bug?

Here's the entire relevant portion of my code,

@IBOutlet weak var theTabView: NSTabView?
@IBOutlet weak var tabViewDelegate: NSTabViewController?
    override func assignMainView() {
    ControllersRef.sharedInstance.tabViewController = self.tabViewController
    ControllersRef.sharedInstance.theTabView = self.theTabView
    ControllersRef.sharedInstance.thePrefPane = self
    let tabs = ["Internet", "URL Schemes", "Uniform Type Identifiers", "Applications"]

    if let tabViewDelegate = self.tabViewDelegate {
        for tab in tabs {
            let newTab = NSTabViewItem(viewController: NSViewController.init()) // I tried doing it the other way around also, i.e. via addChildViewController() and tabItem(for:), but the result was the same.

            newTab.label = tab
            let newTabViewItemView = DRYView.init()
            newTabViewItemView.nibName = "SWDAPrefpaneTabTemplate"

            tabViewDelegate.addChildViewController(newTab.viewController!)
            newTab.viewController!.view = newTabViewItemView

        }
        let views = tabViewDelegate.childViewControllers
        tabViewDelegate.tabView = ControllersRef.sharedInstance.theTabView

    }
    super.assignMainView()
}
  • try with an appDelegate variable... – Ananth Feb 25 '17 at 04:46
  • Don't bind to a view, bind to a controller (or document or app delegate). Why do you want to hide and show items on invisible tabs? Can't you hide the views once? – Willeke Feb 25 '17 at 12:26

1 Answers1

1

You should be able to use an NSTabViewController and its selectedTabViewItemIndex property, which is specifically documented to be bindings-compliant.

If you need to, you can create a computed property that's built on top of selectedTabViewItemIndex to map to an appropriate model object for the selected item. When you do that, be sure to implement the class method keyPathsForValuesAffecting<Key> to return ["selectedTabViewItemIndex"] so that KVO knows to consider your computed property as changed whenever selectedTabViewItemIndex changes.

(This is probably not sufficient to make the computed property you already tried work, because NSTabView's selectedTabViewItem itself is not documented as being KVO-compliant.)

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Will try this. One question, though... I'm not really sure how to implement NSTabViewController, and haven't been able to find enough documentation to really help me.Even if I implement an empty NSTabViewController subclass, my NSTabView breaks, tabs stop being selectable (and I get a crash whenever I try to change them)... which is why my current implementation used instead an NSViewController subclass that also conforms to NSTabViewDelegate. – Gregorio Litenstein Feb 25 '17 at 14:57
  • How are you creating your tab view, programmatically or via IB? – Ken Thomases Feb 25 '17 at 19:27
  • Was creating the tab view itself via IB, and adding tabs dynamically via mainViewDidLoad() – Gregorio Litenstein Feb 25 '17 at 21:07