Jeff J Jeff J - 4 months ago 29
Swift Question

Extending the NSTableViewDataSource Protocol with a default method

I would like to add a method with a default to the NSTableViewDataSource protocol. But when I do this, the default is always called, even when the method is defined in the actual data source. Specifically:

I have a single-column NSTableView which can adopt several different data sources at different times. In one case, I would like the data source to be able to provide not only the values displayed, but the background colors of the rows in the table. In the other cases, the table can be a single color. My idea was to first extend the NSTableViewDataSource protocol:

extension NSTableViewDataSource
{
func tableView (tableView: NSTableView, colorIndexForRow row: Int) -> Int
{
return 0
}
}


then in the table delegate I put this:

public func tableView (tableView: NSTableView, didAddRowView rowView: NSTableRowView, forRow row: Int)
{
let colorIndex = tableView.dataSource()!.tableView(tableView, colorIndexForRow: row)
rowView.backgroundColor = rowColors[colorIndex]
}


(rowColors is just an array of NSColor objects, six for experimental purposes.)

Finally, my experimental data source looks like this:

public func numberOfRowsInTableView (tableView: NSTableView) -> Int
{
return 100
}

public func tableView (tableView: NSTableView, objectValueForTableColumn column: NSTableColumn?, row: Int) -> AnyObject?
{
return String(format: "This is row %3i", row)
}

public func tableView (tableView: NSTableView, colorIndexForRow row: Int) -> Int
{
return row % 6
}


I expected this to produce a table in which the rows were in a rotating cycle of six colors. What I actually get is a table all in the color of rowColors[0]. The default for my colorIndexForRow method is always called, even though I provide the method in my data source. My reading of Swift documentation is that the default in a protocol extension is supposed to be called only when an actual method isn’t there. Can anyone tell me what I’m doing wrong?

Answer

The reason is because protocol extension doesn't support class polymorphism.

You can rewrite your function as:

public func tableView (tableView: NSTableView, didAddRowView rowView: NSTableRowView, forRow row: Int)
{ 
    let colorIndex = self.tableView(tableView, colorIndexForRow: row)
    rowView.backgroundColor = rowColors[colorIndex]
}