When creating an instance of a custom NSTableCellView how do pass in a value

I have a program that creates a custom table view. In the delegate that populates the cells with data I create an instance of a custom NSTableCellView. It works. What I would like to be able to do is pass in a value when making an instance so that I can set the width of the frame (var rectWidth in the custom NSTableCellView). I am currently using two different custom NSTableCellViews, each with a different value for var rectWidth. Below is my delegate and custom NSTableCellView code.

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    if (tableColumn?.identifier)!.rawValue == "fund" {
        let dataCell = CustomTableCellView()
        dataCell.textField?.stringValue = closingValues[row].fundName
        return dataCell
    } else if (tableColumn?.identifier)!.rawValue == "date" {
        let dataCell = CustomTableCellViewDate()
        dataCell.textField?.stringValue = SQLDateFormatter.string(from: closingValues[row].timeStamp)
        return dataCell
    } else {
        let dataCell = CustomTableCellView()
        dataCell.textField?.stringValue = String(format: "$%.2f", closingValues[row].close)
        return dataCell
    }
}

class CustomTableCellView: NSTableCellView {
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        let rectWidth: CGFloat = 100
        self.autoresizingMask = .width
        let nsRectangle = NSMakeRect(0, 0, rectWidth, 24)
        let customTextField: NSTextField = CustomTextField(frame: nsRectangle)
        self.textField = customTextField
        self.addSubview(customTextField)
    }
    required init?(coder decoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Accepted Reply

The problem appears to be that once I create an instance of CustomTableCellView, the variable nsRectangle is assigned a value based on the current rectWidth value in the override init. And of course your can only override a pre-existing init, none of which include rectWidth. So changing the value of rectWidth after the instance has been created appears to be of no value since the init is only run once. My solution was to pull all of the logic out of the CustomTableCellView init and place it into a function in CustomTableCellView. Then I can create an instance of CustomTableCellView in my Coordinators delegate, which only runs a call to super.init(). On the following line I call the function, named Setup(), to which I pass in rectWidth. The side benefit is this allowed me to simplify the Coordinators delegate code. Below are the updated delegate and CustomTableCellView code. Claude31, thank you for your response.

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

    let dataCell = CustomTableCellView()
    if (tableColumn?.identifier)!.rawValue == "fund" {
        dataCell.Setup(rectWidth: 100.0)
        dataCell.textField?.stringValue = closingValues[row].fundName
    } else if (tableColumn?.identifier)!.rawValue == "date" {
        dataCell.Setup(rectWidth: 120.0)
        dataCell.textField?.stringValue = SQLDateFormatter.string(from: closingValues[row].timeStamp)
    } else {
        dataCell.Setup(rectWidth: 100.0)
        dataCell.textField?.stringValue = String(format: "$%.2f", closingValues[row].close)
    }
    return dataCell
}

class CustomTableCellView: NSTableCellView {
    
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
    }
    func Setup(rectWidth: CGFloat) {
        self.autoresizingMask = .width
        let nsRectangle = NSMakeRect(0, 0, rectWidth, 24)
        let customTextField: NSTextField = CustomTextField(frame: nsRectangle)
        self.textField = customTextField
        self.addSubview(customTextField)
    }
    required init?(coder decoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Replies

It may depend how much data you want to pass.

But for simple data, you could set the tag when you create the cell.

cell.tag = rectWidth

And even pass the rect size, by multiplexing:

cell.tag = rectWidth + 8000 * rectHeight  // 8000 is large enough so that it will be larger than any width

and use it by demultiplexing

let width = cell.tag % 8000
let height = (cell.tag - width) / 8000

The problem appears to be that once I create an instance of CustomTableCellView, the variable nsRectangle is assigned a value based on the current rectWidth value in the override init. And of course your can only override a pre-existing init, none of which include rectWidth. So changing the value of rectWidth after the instance has been created appears to be of no value since the init is only run once. My solution was to pull all of the logic out of the CustomTableCellView init and place it into a function in CustomTableCellView. Then I can create an instance of CustomTableCellView in my Coordinators delegate, which only runs a call to super.init(). On the following line I call the function, named Setup(), to which I pass in rectWidth. The side benefit is this allowed me to simplify the Coordinators delegate code. Below are the updated delegate and CustomTableCellView code. Claude31, thank you for your response.

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {

    let dataCell = CustomTableCellView()
    if (tableColumn?.identifier)!.rawValue == "fund" {
        dataCell.Setup(rectWidth: 100.0)
        dataCell.textField?.stringValue = closingValues[row].fundName
    } else if (tableColumn?.identifier)!.rawValue == "date" {
        dataCell.Setup(rectWidth: 120.0)
        dataCell.textField?.stringValue = SQLDateFormatter.string(from: closingValues[row].timeStamp)
    } else {
        dataCell.Setup(rectWidth: 100.0)
        dataCell.textField?.stringValue = String(format: "$%.2f", closingValues[row].close)
    }
    return dataCell
}

class CustomTableCellView: NSTableCellView {
    
    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
    }
    func Setup(rectWidth: CGFloat) {
        self.autoresizingMask = .width
        let nsRectangle = NSMakeRect(0, 0, rectWidth, 24)
        let customTextField: NSTextField = CustomTextField(frame: nsRectangle)
        self.textField = customTextField
        self.addSubview(customTextField)
    }
    required init?(coder decoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}