Попытка использовать 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, включая такие, как указание заполнителей для использования. если пользователь выбирает более одного объекта одновременно. Это действительно хорошо.