UITableView — один из наиболее часто используемых компонентов пользовательского интерфейса в Swift, поскольку большинству современных приложений требуется какой-либо список для отображения похожих элементов, будь то продукты, контакты или фотографии.

Для этой цели UITableViewCell представляет собой атом списка, определяя схему того, как должен выглядеть отдельный элемент этого списка. Что ж, все может очень быстро усложниться, поскольку оказывается, что существует несколько способов создать UITableViewCell в Swift.

В этой статье мы рассмотрим различные способы создания и регистрации ячейки в табличном представлении. Что мы рассмотрим:

  1. Как создать и зарегистрировать NIB из файла XIB
  2. Как создать и зарегистрировать подкласс UITableView, созданный программно
  3. Как повторно использовать программную ячейку внутри раскадровки.

Готовый? Давайте погрузимся! 🏊‍♀️

1. Первоначальная настройка проекта

  1. Создайте новый проект iOS и дайте ему любое имя. Обязательно выберите Storyboard в качестве интерфейса вместо SwiftUI.
  2. Для простоты оставьте все сгенерированные файлы как есть и откройте Main.storyboard.
  3. Добавьте кнопку, дайте ей красивое имя, откройте ViewController.swift и подключите IBAction для события Touch Up Inside. Мы будем использовать это действие, чтобы показать класс табличного представления.

4. Создайте новый файл Swift с именем TableController и сделайте его подклассом UITableViewController.

2. Использование построителя интерфейса XCode для создания NIB

  1. Создайте новый Cocoa Touch Class, подкласс UITableViewCell, и обязательно установите флажок «Также создать файл XIB» флажок.
  2. Откройте только что созданный файл XIB, перетащите на него UILabel и настройте его ограничения.
  3. Подключите метку к файлу Swift пера, создав для него соединение IBOutlet. Ваша установка должна выглядеть так:

4. Вернемся к TableController. Пришло время зарегистрировать этот класс. Внутри viewDidLoad мы делаем это следующим образом:

let nib = UINib(nibName: "NIBTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: NIBTableViewCell.cellIdentifier)

где cellIdentifier — это статическая константа, которую мы определили внутри класса NIBTableViewCell.

«nibName», используемый здесь в конструкторе UINib, должен совпадать с точным именем файла пера, иначе система не сможет найти NIB внутри основного пакета.

5. Реализуйте необходимые методы UITableView, чтобы что-то видеть на экране:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 5
}
    
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: NIBTableViewCell.cellIdentifier, for: indexPath)
    return cell
}

6. Откройте ViewController и внутри метода действия кнопки добавьте логику для модального отображения экрана просмотра таблицы:

@IBAction func openTableAction(_ sender: UIButton) {
    let tableController = TableController()
    present(tableController, animated: true)
}

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

3. Создайте подкласс UITableViewCell программно.

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

  1. Сначала создайте новый файл Swift и сделайте его подклассом UITableViewCell.
  2. Реализуйте два необходимых инициализатора:
init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)

required init?(coder: NSCoder)

3. Создайте метод setup(), в котором мы настроим представление и добавим необходимые ограничения:

func setup() {
    contentView.addSubview(label)
    
    label.text = "Programatic Cell Label"
    label.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
        label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
        label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20)
    ])
}

Здесь я установил другой текст для метки, просто чтобы было понятно, что мы будем использовать другую ячейку.

4. Вызовите метод setup() внутри каждого инициализатора.

5. Вернувшись внутрь TableController, мы комментируем регистрацию старого пера и заменяем его следующим кодом:

tableView.register(ProgramaticCell.self, forCellReuseIdentifier: ProgramaticCell.cellIdentifier)

6. Запустите приложение еще раз, и вы увидите, что отображается новая ячейка. 🎉

4. Используйте программный UITableViewCell внутри раскадровки

Теперь, когда ячейка табличного представления создана, мы можем повторно использовать ее во многих местах нашего кода, в том числе в файле раскадровки.

  1. Создайте новый файл Storyboard с именем Table, удалите сгенерированную сцену View Controller и перетащите объект Table View Controller.
  2. Откройте Identity Inspector на этом контроллере таблицы и задайте его пользовательский класс как наш TableController и задайте уникальный идентификатор раскадровки, который мы будем использовать далее . Я назвал его удобным TableVC.

3. Выберите Table View Cell в построителе интерфейса слева и сделайте то же самое, т. е. установите для его пользовательского класса наш класс ProgramaticCell.

4. Теперь у нас есть два варианта: либо продолжить регистрацию нашей ячейки программно, используя метод register, который мы написали ранее внутри TableController, либо сделать это внутри раскадровки. Хотя я предпочитаю первую версию, для целей этого урока давайте сделаем это с помощью раскадровки.

5. Снова выберите Ячейка табличного представления в построителе интерфейса и откройте инспектор атрибутов. В строке Идентификатор напишите уникальный идентификатор, например ProgramaticCellIdentifier. Теперь вы можете удалить метод register, так как он больше не нужен. 🗑️

6. Теперь, когда мы связали нашу раскадровку с нашими пользовательскими классами, давайте вернемся к классу ViewController, чтобы изменить создание нашего контроллера представления.

7. Замените код внутри openTableAction на:

let storyboard = UIStoryboard(name: "Table", bundle: nil)
let tableController = storyboard.instantiateViewController(withIdentifier: "TableVC")
present(tableController, animated: true)

8. Наконец, запустите симулятор еще раз, чтобы увидеть результат.

5. Бонусный раздел: рефакторинг

Вы могли заметить, что для каждого определения ячейки, как для NIB, так и для программного класса, мы должны были определить уникальный идентификатор, чтобы UITableView мог его правильно идентифицировать. Это может стать громоздким и без обеспечения безопасности типов может привести к неожиданным ошибкам разработчика.

К счастью для нас, мы можем создать расширение для класса UITableViewCell, чтобы сгенерировать для нас уникальный reuseIdentifier на основе имени класса, например:

extension UITableViewCell {
    static var reuseIdentifier: String {
        return String(describing: self)
    }
}

Таким образом, нам не нужно придумывать собственные уникальные идеи, у нас есть безопасный способ доступа к ним, и мы можем с уверенностью сказать, что все идентификаторы будут уникальными.

Таким образом, мы:

✅ не нужно придумывать собственные уникальные идеи

✅ иметь безопасный способ доступа к идентификатору повторного использования

✅ можно с уверенностью сказать, что все идентификаторы уникальны

Довольно аккуратно, правда?

Полный демонстрационный проект можно найти здесь.

Спасибо за прочтение! 👏🏼

Следите за последними статьями, нажав кнопку «Подписаться»!