Попытка использовать NSTableView

Я разработчик iOS и создаю свое первое приложение для Mac. Встречаясь с некоторыми трудностями при попытке использовать NSTableView.

extension HomeViewController:NSTableViewDataSource{
    func numberOfRows(in tableView: NSTableView) -> Int {
        print(self.customerApplicationList.count) // '1' gets printed here
        return self.customerApplicationList.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
        var result:NSTableCellView
        result  = tableView.make(withIdentifier: "firstName", owner: self) as! NSTableCellView
        result.textField?.stringValue = "test"
        return result
    }
}

Почему там нет ячейки со значением "тест"? (во время выполнения не включал скриншот этого)

1 ответ

Решение

Если вы поставите журнал в вашем tableView(_:viewFor:row:) метод, вы обнаружите, что он никогда не вызывается. Почему это, вы можете спросить? Ну, это сложно:

AppKit, как мы все знаем, не реализован с использованием Swift; это реализовано в Objective-C. Objective-C, будучи очень динамичным языком, позволяет вызывающей стороне запрашивать, отвечает ли объект на определенное сообщение, поэтому все, что нужно сделать объекту, это реализовать метод, подобный -tableView:viewForTableColumn:row: и с помощью магии Objective-C AppKit может найти метод и вызвать его. С Swift все немного сложнее, потому что по умолчанию методы Swift не доступны Objective-C, если мы явно не сделаем это через @objc ключевое слово, если метод является переопределением метода суперкласса Objective-C, или если метод удовлетворяет протоколу Objective-C. Третий из этих случаев должен происходить здесь, за исключением того, что оказывается, что tableView(_:viewFor:row:) на самом деле принадлежит NSTableViewDelegate не NSTableViewDataSource, Следовательно, компилятор Swift не видит ваш метод как удовлетворяющий какому-либо протоколу, и он не подвергается воздействию Objective-C. Так что с точки зрения AppKit, это как если бы вы не реализовали его вообще.

Чтобы решить вашу непосредственную проблему, добавьте NSTableViewDelegate к вашему расширению, и убедитесь, что ваш источник данных установлен как делегат в Интерфейсном Разработчике. Тем не менее, когда я создаю приложения для Mac, мне проще использовать привязки Какао для заполнения табличных представлений, так как вы получаете множество функций "бесплатно", таких как автоматическая сортировка по столбцам, выбор с опережением ввода и управление выбором. Для этого выполните следующие действия:

1) Убедитесь, что свойство массива на вашем объекте помечено как @objc и dynamic ключевое слово, и что класс, содержащийся в массиве, является NSObject подкласс, и имеет соответствующие свойства также помечены @objc а также dynamic:

class Thingy: NSObject {
    @objc dynamic var name: String

    init(name: String) { self.name = name }
}

class MyViewControllerThingy: NSViewController {
    @objc dynamic var myArray: [Thingy] = [Thingy(name: "Foo"), Thingy(name: "Bar")]
}

Это гарантирует, что AppKit может использовать свою динамическую магию Objective-C, чтобы автоматически сделать это свойство совместимым с KVO, поэтому нам не нужно делать это самостоятельно (это необходимо, потому что привязки Cocoa построены на KVO).

2) Создайте контроллер массива в Интерфейсном Разработчике и в инспекторе привязок установите "Путь к ключу модели" контроллера массива на имя вашего свойства:

3) Теперь выберите ваше табличное представление и в инспекторе привязок свяжите его содержимое, индексы выбора и дескрипторы сортировки с arrangedObjects, selectionIndexes, а также sortDescriptors соответственно, оставляя "Путь к ключу модели" пустым для каждого:

4) Выберите текстовое поле в ячейке табличного представления, перейдите к его инспектору привязок и свяжите его с представлением ячейки таблицы, указав путь к ключу модели objectValue. а затем имя свойства, которое вы хотите просмотреть в ячейке:

5) И, наконец, выберите столбец таблицы и задайте для его ключа сортировки имя свойства в Инспекторе атрибутов (поле "Селектор" позволяет вам настроить метод вызова объектов для их сортировки; мне нравится использовать localizedStandardCompare: для строк, чтобы получить сортировку без учета регистра, но для большинства других типов вы можете просто оставить это по умолчанию):

И вуаля:

В Интерфейсном Разработчике это может показаться сложным, но в конце мы настроили всю таблицу практически без кода. Кроме того, мы получаем по-настоящему удобный пользовательский интерфейс для ваших пользователей, а также множество бесплатных функций. Моим любимым вариантом является автоматическая сортировка, нажав на заголовки:

Самое замечательное в этом не только то, что вам не нужно беспокоиться о повторной сортировке массива самостоятельно, но это даже не портит порядок вашего исходного массива; изменение только для отображения. Массив здесь еще ["Foo", "Bar"],

Еще одна действительно крутая особенность NSArrayController является то, что он будет управлять выбором для вас. Например, если ваше табличное представление является боковой панелью, вы можете привязать другое представление справа к выбранному объекту в контроллере массива, и таким образом вы можете легко реализовать такие вещи, как средство просмотра панели Mail.app, включая такие, как указание заполнителей для использования. если пользователь выбирает более одного объекта одновременно. Это действительно хорошо.

Другие вопросы по тегам