9

As title. How does the NSTableView set content Mode(view-based or cell-based) by code?

Thanks for helping

CocoaUser
  • 1,361
  • 1
  • 15
  • 30
  • I looked through the .h files for NSTableView, NSTableViewDelegate and NSTableViewDataSource and didn't see anything *obvious* in there. I suspect the way NSTableView works in code is that it attempts to fetch a view first and if that doesn't work, it'll do cell-based. Either way, 99% of developers will select "View" or "Cell" via the popup in Interface Builder. – Michael Dautermann Oct 07 '13 at 07:21

1 Answers1

11

NSTableView defaults to being cell-based, which makes sense for backwards compatibility. Table views are view-based when the table view delegate implements -tableView:viewForTableColumn:row:. You can easily test by programmatically creating a table view as follows:

@implementation BAVAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSView *contentView = self.window.contentView;
    NSTableView *tableView = [[NSTableView alloc] initWithFrame:(NSRect){{50, NSMaxY(contentView.frame) - 200}, {400, 200}}];
    tableView.dataSource = self;
    tableView.delegate = self;
    [contentView addSubview:tableView];

    NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:@"column"];
    column.width = 400;
    [tableView addTableColumn:column];
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
    return 3;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    return [NSString stringWithFormat:@"%ld", row];
}

//- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
//    NSTextField *textField = [[NSTextField alloc] initWithFrame:(NSRect){.size = {100, 15}}];
//    textField.stringValue = [NSString stringWithFormat:@"%ld", row];
//    return textField;
//}

@end

If you run this code with that delegate method commented out, you get a cell-based table view:

enter image description here

And if you uncomment that delegate method, you get a view-based table view:

enter image description here

The documentation for -tableView:viewForTableColumn:row: states that

This method is required if you wish to use NSView objects instead of NSCell objects for the cells within a table view. Cells and views can not be mixed within the same table view.

which hints at it being the condition that determines whether a table view is cell- or view-based.

  • You won't find a more complete answer than this. – uchuugaka Oct 07 '13 at 08:33
  • 3
    Don't skip adding the `NSTableColumn` as seen in `-applicationDidFinishLaunching` above! I missed that portion of the answer several times. – waggles Feb 28 '14 at 19:21
  • 1
    Thank you @waggles! That was the bit that I was missing, but assumed I had the "content mode" issue. – Giles Nov 27 '17 at 13:31
  • Also, if you're planning to subsequently make your `NSTableViewCell` programmatically, then you CANNOT use [NSTableView.makeView(withIdentifier:owner:)](https://developer.apple.com/documentation/appkit/nstableview/1535482-makeview); see [this discussion](https://stackoverflow.com/a/51736602/5951226) for the reasoning and solution. – Jamie Birch Aug 07 '18 at 23:09