You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更新编程创建的NSTableView数据源:编辑单元格后同步数据

解决视图型NSTableView单元格编辑后更新数据源的问题

核心思路

视图型NSTableView无法使用单元格型表格的tableView(_:setObjectValue:for:row:)方法,必须给单元格内的NSTextField绑定target-action,在编辑结束时触发自定义逻辑,更新数据源对应位置的数据。

具体实现步骤

1. 自定义单元格(推荐方案)

自定义单元格类来存储当前单元格对应的行、列索引,避免用tag或关联对象的繁琐操作:

class EditableTableCellView: NSTableCellView {
    // 存储当前单元格的行、列索引
    var rowIndex: Int = 0
    var columnIndex: Int = 0
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // 给文本框绑定编辑结束的触发事件
        textField?.target = self
        textField?.action = #selector(textFieldEditFinished(_:))
    }
    
    @objc private func textFieldEditFinished(_ textField: NSTextField) {
        // 通过通知把编辑信息传递给控制器
        NotificationCenter.default.post(
            name: NSNotification.Name(rawValue: "TableCellEdited"),
            object: self,
            userInfo: [
                "row": rowIndex,
                "column": columnIndex,
                "newValue": textField.stringValue
            ]
        )
    }
}

2. 配置单元格并绑定索引

在数据源方法中,给自定义单元格设置对应的数据和索引:

// 假设你的数据源是可变二维数组
var yourDataSource: [[String]] = []

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    guard let columnIndex = tableView.tableColumns.firstIndex(of: tableColumn!) else { return nil }
    let cellID = NSUserInterfaceItemIdentifier("EditableCell")
    
    // 获取或创建自定义单元格
    let cell = tableView.makeView(withIdentifier: cellID, owner: self) as? EditableTableCellView ?? EditableTableCellView(identifier: cellID)
    
    // 设置单元格内容
    cell.textField?.stringValue = yourDataSource[row][columnIndex]
    // 绑定当前行、列索引
    cell.rowIndex = row
    cell.columnIndex = columnIndex
    // 开启编辑权限
    cell.textField?.isEditable = true
    
    return cell
}

3. 监听编辑事件并更新数据源

在控制器中监听通知,处理数据源更新:

override func viewDidLoad() {
    super.viewDidLoad()
    // 监听单元格编辑完成的通知
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(updateDataSource(_:)),
        name: NSNotification.Name(rawValue: "TableCellEdited"),
        object: nil
    )
}

@objc private func updateDataSource(_ notification: Notification) {
    guard let userInfo = notification.userInfo,
          let row = userInfo["row"] as? Int,
          let column = userInfo["column"] as? Int,
          let newValue = userInfo["newValue"] as? String else { return }
    
    // 检查索引合法性,防止越界崩溃
    guard row < yourDataSource.count, column < yourDataSource[row].count else { return }
    
    // 更新数据源
    yourDataSource[row][column] = newValue
}

// 控制器销毁时移除通知监听,避免内存泄漏
deinit {
    NotificationCenter.default.removeObserver(self)
}

替代方案:直接绑定控制器(无需自定义单元格)

如果不想自定义单元格,可直接在数据源方法中给系统单元格的文本框绑定目标和动作,用关联对象存储行索引:

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
    guard let columnIndex = tableView.tableColumns.firstIndex(of: tableColumn!) else { return nil }
    let cellID = NSUserInterfaceItemIdentifier("EditableCell")
    let cell = tableView.makeView(withIdentifier: cellID, owner: self) as? NSTableCellView ?? NSTableCellView(identifier: cellID)
    
    cell.textField?.stringValue = yourDataSource[row][columnIndex]
    cell.textField?.isEditable = true
    // 绑定目标为当前控制器,动作为自定义方法
    cell.textField?.target = self
    cell.textField?.action = #selector(onTextFieldEdited(_:))
    // 列索引存在tag,行索引用关联对象绑定到文本框
    cell.textField?.tag = columnIndex
    objc_setAssociatedObject(cell.textField!, "rowIndex", row, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    
    return cell
}

@objc private func onTextFieldEdited(_ textField: NSTextField) {
    guard let row = objc_getAssociatedObject(textField, "rowIndex") as? Int,
          let column = textField.tag as? Int else { return }
    guard row < yourDataSource.count, column < yourDataSource[row].count else { return }
    
    yourDataSource[row][column] = textField.stringValue
}

注意事项

  • 确保yourDataSource是可变数组(用var声明),不可变数组无法直接修改元素。
  • 必须处理索引越界判断,避免因数据源变化或异常操作导致崩溃。
  • 使用通知方案时,务必在控制器销毁时移除监听,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Cherub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 08:25:22