NSBrowser reuses cell rather than creating new one

392 views Asked by At

I'm trying to create a UI element using NSBrowser, but for some reason the browser creates a singleton instance of the custom cell class that I specify, rather than creating new cell instance for each cell in the browser. In particular, here's the delegate implementation

- (void)awakeFromNib {
    [super awakeFromNib];

    self.browser.target = self;
    self.browser.doubleAction = @selector(_doubleClick:);
    self.browser.reusesColumns = YES;
//    self.browser.cellClass = [CLColumnViewCell class];
    [self.browser setCellPrototype:[[CLColumnViewCell alloc] init]];
}

#pragma mark NSBrowserDelegate

- (void)browser:(NSBrowser *)browser createRowsForColumn:(NSInteger)column inMatrix:(NSMatrix *)matrix {
    NSLog(@"This method never gets called");
}

- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item {
    return [(item ?: _root) countOfContents];
}

- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item {
    return ![(item ?: _root) canHaveContents];
}

- (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item {
    return [(item ?: _root) objectInContentsAtIndex:index];
}

- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item {
    return nil; // Object value is handled by CLColumnViewCell itself.
}

- (void)browser:(NSBrowser *)browser willDisplayCell:(CLColumnViewCell *)cell atRow:(NSInteger)row column:(NSInteger)column {
    NSIndexPath *indexPath = [[browser indexPathForColumn:column] indexPathByAddingIndex:row];
    cell.columnView = browser;
    cell.indexPath = indexPath;
    cell.object = [browser itemAtIndexPath:indexPath];
    NSLog(@"will display cell %@", cell, cell);
}

And the log message looks like this

2012-11-11 09:57:16.582 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.583 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.583 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.584 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.584 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.585 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.585 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.586 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.587 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.587 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.588 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.588 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.589 will diplay cell <CLColumnViewCell: 0x102e597c0>
2012-11-11 09:57:16.589 will diplay cell <CLColumnViewCell: 0x102e597c0>

As the message shows, the same cell instance gets used over and over again! Is there a way to force NSBrowser to create new cell instances rather than reusing the same one?

1

There are 1 answers

0
ipmcc On

Not really. This is, after all, the whole point of NSCell. NSCells are lightweight alternatives to NSViews. This mattered more in the more performance-restricted days of yore -- Indeed, as you'll note Apple has started to make NSView-based alternatives for formerly cell-heavy controls like NSTableView and NSOutlineView. I'm guessing they haven't gotten around to doing an NSView-based NSBrowser. (Although looking at the NSTableView API, it's easy to see why -- the retrofit is kind of clunky. They might have been better off simply starting over., but I digress...)

In short, given that the whole idea of NSCell is to have a lightweight object that can be reused instead of having to reallocate a new one every time, I would be surprised if there were a straightforward way to get it to make a new one every time. You might be able to hack this behavior up by subclassing NSBrowser, but you're probably better off coming up with a different approach.