I have a view-based NSOutlineView
with a dataSource/delegate
model instead of binding to a tree controller (I want control over the insert/update animations).
I'm replacing an item in my model and would like to update that specific row in the outline view without having to call reloadData()
.
I cannot get this to work. Either the item does not update at all or the item's expanded state doesn't update. There seems to be some caching being done inside of NSOutlineView according to this, but even with these suggestions, I could not get it to work.
What I have:
(1) The outline view represents a folder structure
(2) At first, there is a singe file:
(3) The file is then replaced with a folder item:
// Model update
let oldFileItem = rootItem.children.first!
rootItem.children.remove(at: 0)
rootItem.children.append(Item(title: "Folder", children:[], isExpandable:true))
Expected result:
Actual result (reloadItem):
outlineView.reloadItem(oldFileItem) // I kept a reference
Icon and title reloaded, but note that the expansion triangle is missing.
I can somewhat understand that reloadItem() might not work in this case, because the old item is not part of the data model anymore. Strangely enough, the item's title and icon update, but not the expansion state.
Actual result (reloadData(forRowIndexes:columnIndexes:):
outlineView.reloadData(forRowIndexes: IndexSet(integer:0), columnIndexes: IndexSet(integer:0))
No effect whatsoever. This is the one that I would have expected to work.
Actual result (remove/insert):
outlineView.removeItems(at: IndexSet(integer:0), inParent: rootItem, withAnimation: [])
outlineView.insertItems(at: IndexSet(integer:0), inParent: rootItem, withAnimation: [])
No effect whatsoever.
The docs say about removeItems()
: "The method does nothing if parent is not expanded." and isExpanded does indeed return false
for the root node, although its children are visible. Is this special behavior for items that are direct children of the root node? What am I missing here?
For reference, my data model:
class Item:NSObject {
var title:String
var children:[Item]
var isExpandable:Bool
init(title:String, children:[Item], isExpandable:Bool) {
self.title = title
self.children = children
self.isExpandable = isExpandable
}
}
For reference:
It turned out to be an issue with how I used the API. NSOutlineView.removeItems/insertItems
expect nil
for the inParent
parameter for the root item. I was handing in the actual root item. Using nil
instead of the root item solved the problem.