Привязка NSTableView к NSArrayController программно - PullRequest
0 голосов
/ 07 сентября 2018

Я пытаюсь связать NSTextView с NSArrayController в коде и следил за несколькими вопросами, уже заданными по этому вопросу: здесь , здесь и здесь . Я создаю приложение MacOS, используя Xcode 9.2 и Swift 4.

У меня есть SegmentedControl с 2 кнопками: одна для добавления нового объекта, а другая для удаления. У меня сбой при попытке привязать NSTextField к вновь созданному объекту, добавленному в массив.

Мой код для VeiwController:

private enum Columns {
  static let name = NSUserInterfaceItemIdentifier("NameColumn")
  static let age = NSUserInterfaceItemIdentifier("AgeColumn")
}

let arrayController: NSArrayController

let table: NSTableView

let buttons: NSSegmentedControl

// MARK: —Initialisation—

required init() {
  super.init(nibName: nil, bundle: nil)
  /// Code to create arrayController, table, and buttons 
  ///...

  /// Bindings.
  table.bind(.content,
             to: self.arrayController,
             withKeyPath: "arrangedObjects",
             options: nil)
  /// Delegates
  table.delegate = self
  buttons.target = self
  buttons.action = #selector(splitButtonClicked)
}

Функция добавления / удаления объектов из arrayController. Person - это простой класс с 2 свойствами (Name и Age):

@objc func splitButtonClicked() {
  switch buttons.selectedSegment {
  case 0:
    let person = Person()
    person.name = "Alfred"
    person.age = 21
    arrayController.addObject(person)
   case 1:
    arrayController.removeObject(arrayController.selectedObjects)
  default:
    print("Switch case error")
  }
}

Код для создания новой строки таблицы возвращает новый NSTextField, но у меня происходит сбой при попытке привязать текстовое поле, и я не уверен, почему:

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
  guard let column = tableColumn else { return nil }
  let t = NSTextField(frame: NSRect(x: 0, y: 0, width: column.width, height: table.rowHeight))
  if column.identifier == Columns.name {
    /// Crashing on this line.
    t.bind(.value, to: t, withKeyPath: "objectValue.name", options: nil)
  } else if column.identifier == Columns.age {
    t.bind(.value, to: t, withKeyPath: "objectValue.age", options: nil)
  }
  return t
} 

1 Ответ

0 голосов
/ 07 сентября 2018

Эти 2 строки:

let t = NSTextField(...)
t.bind(.value, to: t, withKeyPath: "objectValue.name", options: nil)

Вы привязываете текстовое поле к себе по несуществующему пути ключа. Если развернуть иерархию представления табличного представления, оно будет выглядеть следующим образом:

Table View > Column > Cell View > Text Field

Вам необходимо предоставить Вид ячейки с текстовым полем, вложенным внутрь.

fileprivate extension NSUserInterfaceItemIdentifier {
    static let cellView = NSUserInterfaceItemIdentifier("CellView")
    static let name = NSUserInterfaceItemIdentifier("NameColumn")
    static let age = NSUserInterfaceItemIdentifier("AgeColumn")
}

extension ViewController: NSTableViewDelegate, NSTableViewDataSource {
    private func makeCell(frame: CGRect) -> NSTableCellView {
        // Reuse an existing cell if possible
        if let existingCell = table.makeView(withIdentifier: .cellView, owner: nil) as? NSTableCellView {
            return existingCell
        }

        // Make a new cell
        let textField = NSTextField(frame: frame)
        textField.drawsBackground = false
        textField.isBordered = false

        let cell = NSTableCellView(frame: frame)
        cell.identifier = .cellView
        cell.textField = textField
        cell.addSubview(textField)
        return cell
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        guard let column = tableColumn else { return nil }

        let cell = makeCell(frame: NSRect(x: 0, y: 0, width: column.width, height: table.rowHeight))

        // Varying the binding based on what column is being requested
        switch column.identifier {
        case .name:
            cell.textField?.bind(.value, to: cell, withKeyPath: "objectValue.name", options: nil)
        case .age:
            cell.textField?.bind(.value, to: cell, withKeyPath: "objectValue.age", options: nil)
        default:
            print("Unrecognized column '\(column.identifier)'")
        }
        return cell
    }
}
...