17

I'm trying to release some strain on a view-based NSOutlineView for which I changed a single item property and which I initially reloaded just fine using [myOutlineView reloadData].

I tried [myOutlineView reloadItem: myOutlineViewItem] but it never calls - (NSView *)outlineView:(NSOutlineView *)ov viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item and consequently the data is not updated.

-(void)reloadOutlineViewObject
{
    //[myOutlineView reloadData];   //Reload data just fines but is ressource-hungry
    NSLog(@"%d",[myOutlineView rowForItem:myOutlineViewItem]; //Making sure my object is an item of the outlineView, which it is !
    [myOutlineView reloadItem:myOutlineViewItem];   
}

Am I missing something here ?

UPDATE

As pointed out in the comments, my outlineView is view-based.

UPDATE 2

Trying out some stuffs made me realized that the object I am reloading is a second-level object (cf object tree) and calling reloadItem:firstLevelObject reloadChildren:YES does work.

Would it be possible that we can only call reloadItem: on first-level object ? That would be highly inefficient in my case (I only have one two level item and plenty of second level) !

nil ->firstLevelA ->secondLevel1
                  ->secondLevel2
    ->firstLevelB ->secondLevel3
                  ->secondLevel4

Gonna try to subclass NSOutlineView and rewrite reloadItem: in the mean time.

UPDATE 3

I took a look at NSOutlineView in Cocotron to get start and felt that the code I needed to write to overwrite reloadItem would be quiet heavy. Anyone to confirm ?

Community
  • 1
  • 1
Bertrand Caron
  • 2,525
  • 2
  • 22
  • 49

4 Answers4

16

I encountered this same problem with a view-based outline view, where calling -reloadItem: seems to just not do anything. This definitely seems like a big bug, though the documentation doesn't explicitly say that reloadItem will reacquire the views for that row.

My workaround was to call NSTableView's -reloadDataForRowIndexes:columnIndexes: instead, which seems to work as expected, triggering a call to the -outlineView:viewForTableColumn:item: delegate method for just that item. You can get the row that needs to be reloaded by calling -rowForItem: and passing in the item you want to reload.

Brian Webster
  • 11,915
  • 4
  • 44
  • 58
  • 1
    Also just tried calling `-reloadItem:reloadChildren:` on the item's parent, and that seems to work as long as you pass YES for reloadChildren. But of course that reloads *all* the children, not just the one item. – Brian Webster Mar 18 '14 at 22:03
  • Thanks ! As you can imagine, I quite out of sync with the project right now, it may take some time for me to validate the answer ;) – Bertrand Caron Mar 19 '14 at 10:12
  • 1
    I was very optimistic after seeing this but unfortunately it doesn't work for me either. – greg Sep 14 '14 at 00:55
  • I also ran into this issue. Still a problem as of Jan 2015. Only `-reloadRowIndexes:columnIndexes:` worked for me. Almost thought it didn't because I was passing in the wrong row index (hint: make *sure* you ask the outline view for `-rowForItem:` - duh! :-)). – Joshua Nozzi Jan 04 '15 at 19:26
  • @BrianWebster How did you call `-reloadRowIndexes:columnIndexes:` on an NSOutLineView? I cannot even find that method under the NSTableView – Just a coder Jun 17 '15 at 03:31
  • 1
    Ah, typoed the method name: it's actually `-reloadDataForRowIndexes:columnIndexes:`. Fixed in the answer now. – Brian Webster Jun 24 '15 at 23:27
  • Calling `-reloadDataForRowIndexes:columnIndexes:` works just fine as a workaround for me. For those interested, I submitted a bug report for this back in January of 2015. rdar://19370431 -- it's definitely a 100% reproducible `NSOutlineView` bug that causes `-reloadItem:` *not* to ask its data source for the prepped cell view(s) for the item's row, denying us the chance to update the cell view(s) with new values. Reloading the item's parent via `-reloadItem:item.parent reloadChildren:YES` also works, but misses the point of only reloading one child (esp. if parent is root). – Joshua Nozzi Aug 31 '15 at 18:13
  • Aggravatingly, this solution is not working for me. The only thing that will trigger the change is a full reload, which is obviously suboptimal :( – Ash Jan 02 '16 at 13:48
  • Same issue here. None of the mentioned solutions work. Xcode 11. Cannot reload a group row individually. – vomi Nov 28 '19 at 12:55
  • I'm running into a similar issue with `NSOutlineView`. Beware that `-reloadDataForRowIndexes:columnIndexes:` (at least for an outline view) does NOT reload the item, i.e. while the view is reloaded, it might still show the old values, because the internal data structure is not reloaded. See: https://stackoverflow.com/questions/60397648/nsoutlineview-row-not-editable-by-return-key-anymore-after-reloading-a-differe – Mark Feb 26 '20 at 08:24
11

This really isn't a bug - it was something I had explicitly designed. My thought was that reloadItem (etc) should just reload the outline view item properties, not the table cell at that item, since it doesn't carry enough specific information on what to reload (such as what specific cell you might want reloaded). I had intended for people to use reloadDataForRowIndexes:columnIndexes: to reload a particular view based tableview cell; we usually don't provide cover methods when the base class can easily do the same thing with just a few lines of code.

However, having said that, I know multiple people have gotten confused about this, and most people expect it to reload the cell too.

Please log a bug requesting Apple to change this.

thanks, -corbin

Community
  • 1
  • 1
corbin dunn
  • 2,647
  • 1
  • 18
  • 16
4

Apple seems to have "fixed" it.

WWDC 2016, presentation 203 "What's New in Cocoa" at 30:35 in the video:

"NSOutlineView

  • Reloads cell views associated with the 'item' when reloadItem() is called"
thetrutz
  • 1,395
  • 13
  • 12
2

reloadItem: works only on macOS 10.12.

From release notes: https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKit/

NSOutlineView will now reload the cell views associated with ‘item’ when [outlineView reloadItem:] is called. The method simply calls [outlineView reloadDataForRowIndexes:columnIndexes:] passing the particular row that is to be reloaded, and all the columns. For compatibility, this will only work for applications that link against the 10.12 SDK.

So, if you want to reload row on earlier systems, you should use -reloadDataForRowIndexes:columnIndexes:. Something like that:

let index = outlineView.row(forItem: obj)
let rowIndex = IndexSet(integer: index)

let cols = IndexSet(0 ... outlineView.numberOfColumns) 

outlineView.reloadData(forRowIndexes: rowIndex, columnIndexes: cols)
Shmidt
  • 16,436
  • 18
  • 88
  • 136
  • 1
    How terrible, but it's true, so indeed the MacOs Deployment target determines the bahavior... – Hans Apr 20 '17 at 15:24