我在使用NSTokenFieldCell时遇到了麻烦,所以我继续在Xcode中创建一个新项目来隔离问题。以下是我所做的:
- 将一个NSTableView放到主窗口;
- 选择第二列的文本单元格,并改变它的类(通过身份检查器)为NSTokenFieldCell;
-
实现了一个最小的数据源对象,代码如下:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { return 1; } - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { return @"aa, bb"; }
起初它似乎工作得很好,但如果您双击一个单元格进行编辑,然后tab和shift+tab来回切换单元格,最终当令牌字段单元格接收焦点时,应用程序会因坏访问而崩溃。
我在Lion 10.7.2中使用Xcode 4.2,使用Mac OS X Cocoa应用程序模板附带的所有默认设置。
看起来像Cocoa中的一个bug。如果你打开僵尸,你会看到:
2011-10-31 00:02:43.802 tokenfieldtest[35622:307] *** -[NSTokenFieldCell respondsToSelector:]: message sent to deallocated instance 0x1da761f10
我尝试为表设置一个委托并实现- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
,每次返回一个新的NSTokenFieldCell
(仅用于令牌列),但我得到了相同的错误。
原来的解决方案带来了新的问题。
当NSTableView
未完全显示NSTokenFieldCell
时,进入编辑状态再退出会导致表视图显示异常。
所以我反复尝试找到一个更好的解决方案:
class MyTokenFieldCell: NSTokenFieldCell {
override func fieldEditor(for controlView: NSView) -> NSTextView? {
return nil;
}
}
可能是NSTableView
对NSTokenFieldCell
的编辑器重用机制有问题,导致程序崩溃。
fieldEditorForView:在这里被覆盖,返回nil,这会导致每次编辑时都重新创建编辑器,避免重用,从而解决崩溃问题。
以下是原答案
⚠️由于解决方案会引起其他问题,请忽略
我也遇到过这个问题。我的解决方案是暂时保留表格视图使用的单元格。
Custom NSTokenFieldCell:每次拷贝后,临时保存拷贝。
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 } }
实现
NSTableViewDelegate
的tableView(_:dataCellFor:row:)
方法,为表视图提供MyTokenFieldCell
,并设置标识符为:<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 } }