Search code examples
objective-cmacoscocoansoutlineview

Are the cells in view based NSOutlineView getting released on collapse?


I've never worked before with NSOutlineView and I'm curious if the cells are getting released and deallocated when the item is collapsing?

I feel like my cells are being stacked on top of each other after every time I expand and collapse the item.

Any kind of help is highly appreciated!

HSObjectViewModel* ovm = item;
HSObjectTableCellView *oCell = [outlineView makeViewWithIdentifier:@"OutlineCell" 
                                                             owner:self];
oCell.textField.stringValue = ovm.hsObject.name;
NSImage* im = [[NSImage alloc] init];

if(ovm.isVisible) {
    im = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] 
                                 pathForResource:@"on" ofType:@"png"]];
} else {
    im = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] 
                                 pathForResource:@"off" ofType:@"png"]];
}

[oCell.eyeButton setImage:im];
oCell.eyeButton.target = self;
oCell.eyeButton.action = @selector(visibilityButtonClicked:);
[[oCell.eyeButton cell] setHighlightsBy:0];

Solution

  • There are two types of NSOutlineView. One is view-based (the more flexible one to use) and the other is cell-based. Assuming youre using a view-based, the NSTableCellViews in the outline view will not get deallocated when you collapse an item. The cells simply get de-queued i.e. removed from the screen to be used later.

    This is done for memory effeciency reasons. The logic is "why allocate lets say 2000+ cellViews if the screen is only able to display 20 at a time?" So the cells will get de-queued (to be used later) and not deallocated generally.

    HOWEVER, this behavior is unpredictable. If you set up your code the standard way, then the system will be managing the cells. You cant be 100% sure when a cell will be deallocated. If your users can delete cells from the NSOutlineView, then the chance of cells being deallocated increases.

    -Edit-

    Based on the comments below, you need to reset the cells after dequeuing them. Assuming your code looks something like this.

    - (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
        NSTableCellView *aCellView = [outlineView makeViewWithIdentifier:[tableColumn identifier] owner:self];
    
        // You can reset the cell like so
        if (item.status == 0) {  // Assuming your item has a property called status (you can make what ever property you want)
            aCellView.imageView.image = [NSImage imageNamed:@"redImage"];
        } else if (item.status == 1) {
            aCellView.imageView.image = [NSImage imageNamed:@"blueImage"];
        } else {
            aCellView.imageView.image = nil;
        }
    }
    

    So basically, you observe the properties of the item (properties you should declare to distinguish what item is what) and depending on the property, you reset the cell to show the correct values. In the example above, the cell has a image status 0 = a red image, 1 = blue image, anything else = no image. Had i not reset the cells, when ever i collapse, some cells will have old values of other cells since they are being reused.