Comments 10
Что-то я не совсем понимаю в чем же в итоге смысл и выгода использования UITableViewController'а вместо комбо UIViewController + UITableView. Хорошо когда на экране нет совершенного ничего кроме этой таблицы, но это ведь далеко не всегда так.
Представим такую экран: информация о неком профиле игрока в некой игре. В верхней части экрана у нас расположены юзернейм, аватар и еще какая-нибудь информация, а внизу уже таблица со статистикой/ачивками. Разве в этом случае логично использовать UITableViewController упакованный в контейнер? Получается вместо одного view controller'а на котором расположены разные элементы мы получаем view controller в который упакован контейнер в который упакован еще один view controller. Звучит как ненужное усложнение логики. Можно живой пример увидеть?
Представим такую экран: информация о неком профиле игрока в некой игре. В верхней части экрана у нас расположены юзернейм, аватар и еще какая-нибудь информация, а внизу уже таблица со статистикой/ачивками. Разве в этом случае логично использовать UITableViewController упакованный в контейнер? Получается вместо одного view controller'а на котором расположены разные элементы мы получаем view controller в который упакован контейнер в который упакован еще один view controller. Звучит как ненужное усложнение логики. Можно живой пример увидеть?
Согласен с вами в том, что в статье не хватает живых примеров. Спасибо, добавлю. А пока вот:
Большим плюсом подхода, о котором я рассказал в статье, является возможность разбивать функциональность на взаимозаменяемые части, которые потом очен удобно (пере)использовать.
Давайте предположим, что для вашего примера использовальзуется UIViewController + UITableView. Внезапно прилетает задача и вы узнаете, что теперь необходимо «оптимизировать» данный экран для iPad, добавив справа от первого TableView второй (leaderboards, например). В такой ситуации вам придется внедрять реализацию протоколов для второго TableView рядом с реализацией для первого (даже не рядом, а прямо в том же самом месте).
А теперь давайте представим, что используется встроенный UITableViewController. Можно в считанные минуты скопировать экран, рядом с одним контейнером (для левой TableView) положить второй (для правой TableView) и готово. Каждый TableView живет своей отдельной жизнью и может быть переиспользован на других экранах.
Часто так бывает, что экран Leaderboards уже был в iPhone версии приложения и выглядил очень похоже: вверху общая информация, ниже TableView. В iPad версию нужно вставить только TableView. Если использовался встроенный UITableViewController, то можно сразу его и внедрить без необходимости вносить правки в код. Если использовался подход UIViewController + UITableView, то скорее всего придется менять код, чтобы он заработал для другого экрана, поскольку в нем с большой долей вероятности будут зависимости от первого экрана.
Большим плюсом подхода, о котором я рассказал в статье, является возможность разбивать функциональность на взаимозаменяемые части, которые потом очен удобно (пере)использовать.
Давайте предположим, что для вашего примера использовальзуется UIViewController + UITableView. Внезапно прилетает задача и вы узнаете, что теперь необходимо «оптимизировать» данный экран для iPad, добавив справа от первого TableView второй (leaderboards, например). В такой ситуации вам придется внедрять реализацию протоколов для второго TableView рядом с реализацией для первого (даже не рядом, а прямо в том же самом месте).
А теперь давайте представим, что используется встроенный UITableViewController. Можно в считанные минуты скопировать экран, рядом с одним контейнером (для левой TableView) положить второй (для правой TableView) и готово. Каждый TableView живет своей отдельной жизнью и может быть переиспользован на других экранах.
Часто так бывает, что экран Leaderboards уже был в iPhone версии приложения и выглядил очень похоже: вверху общая информация, ниже TableView. В iPad версию нужно вставить только TableView. Если использовался встроенный UITableViewController, то можно сразу его и внедрить без необходимости вносить правки в код. Если использовался подход UIViewController + UITableView, то скорее всего придется менять код, чтобы он заработал для другого экрана, поскольку в нем с большой долей вероятности будут зависимости от первого экрана.
Кроме общего хэдера для таблицы можно ещё разбить таблицу на секции — секция с одними данными, секция с другими данными.
Разница между UITableViewController и UIViewController + UITableView совсем невелика, мне кажется тут всё больше вкусовщина. И переиспользовать можно через тот же Container.
В Swift реализация протоколов с помощью extension очень приятно выглядит — сразу видно что где и разделение:
Это вообще довольно очевидная вещь, по-моему, только вы не показали в статье — как надо :)
Разница между UITableViewController и UIViewController + UITableView совсем невелика, мне кажется тут всё больше вкусовщина. И переиспользовать можно через тот же Container.
В Swift реализация протоколов с помощью extension очень приятно выглядит — сразу видно что где и разделение:
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: MyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCellIdentifier", for: indexPath) as! MyTableViewCell
cell.someDataModel = MyDataModel
return cell
}
}
Не конфигурируем ячейки прямо во ViewController’е, а передаём модель в ячейку и производим конфигурацию там
Это вообще довольно очевидная вещь, по-моему, только вы не показали в статье — как надо :)
Спасибо за дополнение. По поводу extensions:
Когда используются UIViewController + UITableView, а протоколы реализуются в extensions, то очень часто появляются зависимости между основным классом контроллера и extensions. В итоге эти extensions нельзя просто взять и применить к другому контроллеру, на котором, возможно, появится та же таблица.
Если используется отдельный (встроенный) контроллер, то разработчик будет писать модульный код, который потом очень легко переиспользовать.
Когда используются UIViewController + UITableView, а протоколы реализуются в extensions, то очень часто появляются зависимости между основным классом контроллера и extensions. В итоге эти extensions нельзя просто взять и применить к другому контроллеру, на котором, возможно, появится та же таблица.
Если используется отдельный (встроенный) контроллер, то разработчик будет писать модульный код, который потом очень легко переиспользовать.
>Это вообще довольно очевидная вещь, по-моему, только вы не показали в статье — как надо :)
Это вообще довольно спорная вещь, где биндить данные :)
Это вообще довольно спорная вещь, где биндить данные :)
Интересный подход!
Очевидный совет напоследок — не для всех очевидный, видел много примеров кода, где инициализация ячейки происходит в коде контроллера, причем там не по 3 строчки, а по 15. =]
На самом деле, если функционал контроллера невелик — в Swift удобно реализовывать DataSource & Delegate как расширения и выносить в отдельный файл и код основного контроллера будет чистым и понятным. Собственно такая рекомендация в Swift Guidlines.
Спасибо за статью.
Для себя вынес дополнительную пользу про
Для себя вынес дополнительную пользу про
embedded view controller
, а так же правильность добавления/убирания его в коде1) У меня в проектах часто возникает необходимость делать свой базовый ViewController (наследник UIViewController), в котором реализация общей логики или какие то UI конфигурации для всего проекта. В случае использования UITableViewController нужно делать наследника еще для него, с дублированием всех настроек.
2) Конфигурация ячейки из модели — это прямое нарушение MVC, поэтому решение очень спорное.
А если ячейки используются для разных сущностей, делать для каждой отдельную конфигурацию? И вообще не нарушение ли это того же single responsibility?
2) Конфигурация ячейки из модели — это прямое нарушение MVC, поэтому решение очень спорное.
А если ячейки используются для разных сущностей, делать для каждой отдельную конфигурацию? И вообще не нарушение ли это того же single responsibility?
1) Вы можете использовать свой ViewController и вложить в него UITableViewController, как описано в статье. Если все-таки создать наследника и для UITableViewController, то для борьбы с дублирующимся кодом существует множество паттернов. В Swift для этогй цели можно использовать protocol extensions (к сожалению, не всегда). Но если ничего не помогает, то всегда есть первый вариант.
2) Ячейка конфигурируется не из модели, а из ячейки (с использованием модели). Ячейка проставляет значения для своих subviews – не вижу здесь нарушение single responsibility. Само собой, модель должна содержать данные в конечной форме (готовые к представлению), ячейка не должна заниматься парсингом и другими несвойственными ей операциями.
2) Ячейка конфигурируется не из модели, а из ячейки (с использованием модели). Ячейка проставляет значения для своих subviews – не вижу здесь нарушение single responsibility. Само собой, модель должна содержать данные в конечной форме (готовые к представлению), ячейка не должна заниматься парсингом и другими несвойственными ей операциями.
Sign up to leave a comment.
Зачем нужны UITableViewController и UICollectionViewController