NSSourceList not showing text

I got everything working for my hierarchical view, using NSOutlineView and bindings.



Then, I thought I would try out NSSourceList (which is an NSOutlineView with the appearance set to sourceView) and, even with everything apparently configured the same, apart from the appearance, the arrows on the "group" nodes are visible but not the text on any of the nodes.



Any ideas?

My first guess would be that autolayout is collapsing the cells to zero size because there are insufficient constraints. It might be instructive to look at the outline view in the Xcode view debugger, and see what the cells look like.


Does anything change when you select a row? That forces a redraw of the row, which might reveal a view update problem.


Is this a view-based outline view?

Hi Quincey


Indeed there were no constraints at all on the cells!!!


Even after footling around for an hour, I still couldn't get anything visible. So, I changed back to the NSOutlineView, which works straight out of the library.


There's obviously something lacking in the NSSourceList library object. If I get a moment, I might try comparing the two in the storyboard (as source) file.

OK, I figured it out.


The difference between the preconfigured outline view and the preconfigured source list (there isn't actually a NSSourceList, it's just a NSOutlineView with a different preconfiguration) is in the cell identifiers.


In the outline view, there is only one cell in each column, and the cell identifier is left at the default, which means "automatic". In this case, the cell identifier is actually the table column identifier, which is where you typically get the cell identifier from in your "outlineView(:viewFor:item:)" delegate method.


In the source list, there is only one column, but it has two cells (one for the group header and one for the detail row), and they come preconfigured with cell identifiers "HeaderCell" and "DataCell" respectively. Set up that way, you can't follow the usual pattern of using the column identifier, since neither cell matches the column identifier.


To fix this, you can just use the "HeaderCell" and "DataCell" identifiers directly in "outlineView(:viewFor:item:)". Or, you could delete the "DataCell" identifier in IB, which puts the behavior of the detail cell back to match the normal outline view case.


Note that in a source list — or in any NSOutlineView where you use group rows — you need to test for a table column of nil in "outlineView(:viewFor:item:)". If it's nil, you use the (or conceivably a) header cell identifier. If it's not, you use a (or the) data cell identifier or the table column identifier, depending on which strategy you've chosen to adopt.

Thanks Quincey, very interesting, I'll look into the identifier stuff tomorrow.


although I'm actually using bindings instead of the delegate; which might also have an effect.

The documentation for outlineView:viewForTableColumn:item: (https://developer.apple.com/documentation/appkit/nsoutlineviewdelegate/1535566-outlineview) says:


When using Cocoa bindings, this method is optional if at least one identifier has been associated with the table view at design time. If this method is not implemented, the outline view automatically calls makeViewWithIdentifier:owner: with the tableColumn parameter’s identifier and the outline view’s delegate as parameters, to attempt to reuse a previous view or automatically unarchive a prototype associated with the table view.


In other words, you must implement this method if your cell identifier doesn't match the tableColumn identifier, OR you have more than one prototype cell view (since one of them can't match the tableColumn identifier). In the standard source list that IB gives you, both of these conditions are true, so you must implement the method even though you're using bindings.


FWIW, I always recommend against using bindings between a view-based table/outline view and its content. That's because it basically buys you nothing, and the behavior is easier to understand and control if you just use a simple data source instead.

NSSourceList not showing text
 
 
Q