3

我在使用 NSTokenFieldCell 时遇到了问题,因此我继续在 Xcode 中创建一个新项目以隔离问题。这是我所做的:

  • 将 NSTableView 拖放到主窗口中;
  • 选择第二列的文本单元格,并将其 Class(通过 Identity Inspector)更改为 NSTokenFieldCell;
  • 使用以下代码实现了一个最小可能的数据源对象:

    - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
        return 1;
    }
    
    - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
        return @"aa, bb";
    }
    

起初它似乎工作正常,但如果你双击一个单元格进行编辑,然后用 tab 和 shift+tab 来回切换单元格,最终当令牌字段单元格获得焦点时应用程序崩溃并出现 BAD ACCESS。

我在 Lion 10.7.2 中使用 Xcode 4.2,所有默认设置都带有 Mac OS X Cocoa 应用程序模板。

4

2 回答 2

4

看起来像 Cocoa 中的错误。如果你打开僵尸,你会看到:

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

于 2011-10-31T05:05:01.407 回答
0

原来的解决方案带来了新的问题。

NSTokenFieldCell中未完全显示时,NSTableView进入编辑状态再退出会导致表格视图显示异常。

所以我反复尝试获得更好的解决方案:

class MyTokenFieldCell: NSTokenFieldCell {
    override func fieldEditor(for controlView: NSView) -> NSTextView? {
        return nil;
    }
}

可能是NSTableView的编辑器重用机制NSTokenFieldCell有问题,导致程序崩溃。

fieldEditorForView:这里被覆盖,返回nil,应该会导致每次编辑时都要重新创建编辑器,避免重用,从而解决crash问题。


以下是原答案。

⚠️因为解决方案导致其他问题,请忽略。

我也遇到了这个问题。我的解决方案是暂时保留表格视图使用的单元格。

  1. 自定义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
        }
    }
    
  2. 实现 的tableView(_:dataCellFor:row:)方法NSTableViewDelegate,提供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
        }
    }
    
于 2021-05-26T03:16:42.467 回答