The original solution brought a new problem.
When NSTokenFieldCell
is not fully displayed in NSTableView
, entering the editing state and then exiting will cause the table view to display abnormally.
So I tried repeatedly to get a better solution:
class MyTokenFieldCell: NSTokenFieldCell {
override func fieldEditor(for controlView: NSView) -> NSTextView? {
return nil;
}
}
It may be that NSTableView
's editor reuse mechanism for NSTokenFieldCell
has problems, which caused the program to crash.
fieldEditorForView: is overwritten here, returning nil, which should cause the editor to be recreated every time when editing, avoiding reuse, and thus solves the crash problem.
The following is the original answer.
⚠️ Because the solution causes other problems, please ignore it.
I also encountered this problem. My solution is to temporarily keep the cells used by the table view.
Custom NSTokenFieldCell: after each copy, temporarily save the copy.
class MyTokenFieldCell: NSTokenFieldCell {
static var cells = [NSUserInterfaceItemIdentifier: [MyTokenFieldCell]]()
override func copy(with zone: NSZone? = nil) -> Any {
let cell = super.copy(with: zone)
guard let tokenFieldCell = cell as? MyTokenFieldCell else { return cell }
tokenFieldCell.identifier = self.identifier
guard let identifier = tokenFieldCell.identifier else { return cell }
var cells = MyTokenFieldCell.cells[identifier] ?? []
cells.append(tokenFieldCell)
if cells.count > 4 {
cells.removeFirst()
}
MyTokenFieldCell.cells[identifier] = cells
return cell
}
}
Implement the tableView(_:dataCellFor:row:)
method of NSTableViewDelegate
, provide MyTokenFieldCell
for the table view, and set the identifier to: <columnIdentifier>:<row>
extension ViewController: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, dataCellFor tableColumn: NSTableColumn?, row: Int) -> NSCell? {
guard let columnIdentifier = tableColumn?.identifier, columnIdentifier.rawValue == "token" else {
return tableColumn?.dataCell(forRow: row) as? NSCell
}
let cell = MyTokenFieldCell()
cell.isEditable = true
cell.identifier = .init("\(columnIdentifier.rawValue):\(row)")
return cell
}
}