Программирование
Делаем разделы UITableView с вложенными типами
В сегодняшней статье я покажу вам практический пример использования вложенных (nested) типов, создавая UITableView с несколькими разделами.
В сегодняшней статье я покажу вам практический пример использования вложенных (nested) типов, создавая UITableView с несколькими разделами.
Я собираюсь написать вики о Гарри Поттере, которая покажет пользователю некоторую основную информацию о персонажах, местах и классах Хогвартса. Итак, наш список будет состоять из трех разделов, каждый из которых будет содержать список элементов.
Вот каким будет окончательный результат:
Очень простым подходом было бы создание трех объектов, каждый со своим массивом.
При реализации основных функций UITableViewDataSource вам нужно будет считать индексы IndexPath, создав что-то вроде этого:
Такой подход имеет один большой недостаток. Что произойдет, если вы решите изменить порядок разделов?
В таком сценарии вам придется изменить весь код, что сделает практически невозможным создание динамической таблицы, например, с использованием Server-Driven UI.
Гораздо более разумным решением было бы использовать перечисление (enums) для описания всех наших возможных разделов. Еще лучше, что мы можем использовать связанные значения для наших случаев. Но что такое связанные значения в перечислениях? Официальная документация Swift гласит:
…иногда полезно иметь возможность хранить значения других типов вместе с этими значениями перечислений (кейсами, case). Эта дополнительная информация называется ассоциированным значением (associated value) и меняется каждый раз, когда вы используете case в качестве значения в своем коде.
Вы можете использовать перечисления Swift для хранения связанных значений любого заданного типа, и типы значений могут быть разными для каждого случая перечисления, если это необходимо. Перечисления, подобные этим, известны как размеченные объединения (discriminated unions), объединения с тегами (tagged unions) или варианты (variants) в других языках программирования.
По сути, вы можете добавить объект любого типа в перечисления… и эта вещь чрезвычайно полезна в разделах TableView. Давайте посмотрим, как мы можем создать перечисление Section:
Как видите, я создал перечисление с нашими секциями в качестве кейсов.
У каждого варианта есть связанное значение, которое представляет собой массив объектов в этом разделе.
Я также добавил вычисляемую переменную для заголовка самого раздела. Обычно я предпочитаю добавлять вычисляемую переменную, а не прямое значение для подобных вещей. Так понятнее.
Вы могли заметить, что перечисление является вложенным типом класса ViewController. Я запрограммировал так, потому что эти разделы принадлежат только этому классу. Мы не будем использовать их в других контроллерах нашего приложения — поэтому вложенный тип лучше представляет эту связь.
Идеально.
Вторым шагом будет создание источника данных для нашего UITableView.
Для этого мы будем использовать массив Section! Да, массив перечислений.
Давайте создадим функцию, способную это сделать:
Обратите внимание, что персонажи, локации и курсы были созданы ранее. Их также можно получить с сервера… но для простоты я прописал их в своем коде:
privare var characters = Character.exampleList
Где наш Character представляет собой следующую структуру:
Как вы можете видеть в структуре, я использовал вложенные типы по той же причине.
Хорошо, с нашим массивом секций пора реализовать функции UITableViewDataSource и мы увидим, что с перечислением все будет супер чисто и супер понятно:
Давайте проанализируем методы один за другим.
- Функция numberOfSections просто возвращает размер массива. Если мы добавляем или удаляем элементы в списке, разделы всегда будут синхронизированы. Очень круто!
- Функция numberOfRowsInSection имеет переключатель для перечисления, охватывающий все случаи и просто возвращающий размер связанного массива. Как видите, даже здесь, если вы измените количество или порядок ваших разделов, вам не нужно ничего менять.
- Аналогичный подход реализован в функции cellForRowAt. Использование Switch покрывает все случаи и создает ячейки. Обратите внимание на cellIdentifier… мы вернемся к нему позже.
- Последний метод, titleForHeaderInSection, создает заголовок раздела, используя вычисленную переменную перечисления.
Супер просто!
Теперь все наши секции динамические и мы можем их менять просто в функции createDatasource не трогая код где-либо ещё! И это действительно здорово!
Ранее я обращал ваше внимание на идентификатор ячейки… как вы знаете, это постоянная строка, поэтому мы могли бы использовать и вложенные типы, создав такую структуру:
С такой структурой у нас будут все постоянные строки в одном месте, и поддерживать весь код будет намного проще.
Приведенный выше метод позволяет нам настроить динамическую логику для всего источника данных.
Например, нашему пользователю может быть разрешено просматривать определенный раздел или нет. Может быть, бэкэнд может управлять этим. Или, может быть, пользователю нужны особые привилегии.
С помощью простой модификации функции createDatasource мы можем создать эту логику. Перепишем нашу функцию:
Вот и все!
А теперь я могу показать вам весь код класса контроллера:
Надеюсь, вам понравилась эта статья. Удачного программирования и спасибо за чтение.