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()
}
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.)