Pull to refresh

Comments 10

Что-то я не совсем понимаю в чем же в итоге смысл и выгода использования UITableViewController'а вместо комбо UIViewController + UITableView. Хорошо когда на экране нет совершенного ничего кроме этой таблицы, но это ведь далеко не всегда так.
Представим такую экран: информация о неком профиле игрока в некой игре. В верхней части экрана у нас расположены юзернейм, аватар и еще какая-нибудь информация, а внизу уже таблица со статистикой/ачивками. Разве в этом случае логично использовать 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, то скорее всего придется менять код, чтобы он заработал для другого экрана, поскольку в нем с большой долей вероятности будут зависимости от первого экрана.
Так стало чуть яснее. Спасибо!
Тем не менее практических примеров все равно жду.
Кроме общего хэдера для таблицы можно ещё разбить таблицу на секции — секция с одними данными, секция с другими данными.

Разница между 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 нельзя просто взять и применить к другому контроллеру, на котором, возможно, появится та же таблица.
Если используется отдельный (встроенный) контроллер, то разработчик будет писать модульный код, который потом очень легко переиспользовать.
>Это вообще довольно очевидная вещь, по-моему, только вы не показали в статье — как надо :)

Это вообще довольно спорная вещь, где биндить данные :)

Интересный подход!
Очевидный совет напоследок — не для всех очевидный, видел много примеров кода, где инициализация ячейки происходит в коде контроллера, причем там не по 3 строчки, а по 15. =]


На самом деле, если функционал контроллера невелик — в Swift удобно реализовывать DataSource & Delegate как расширения и выносить в отдельный файл и код основного контроллера будет чистым и понятным. Собственно такая рекомендация в Swift Guidlines.

Спасибо за статью.
Для себя вынес дополнительную пользу про
embedded view controller
, а так же правильность добавления/убирания его в коде
1) У меня в проектах часто возникает необходимость делать свой базовый ViewController (наследник UIViewController), в котором реализация общей логики или какие то UI конфигурации для всего проекта. В случае использования UITableViewController нужно делать наследника еще для него, с дублированием всех настроек.
2) Конфигурация ячейки из модели — это прямое нарушение MVC, поэтому решение очень спорное.
А если ячейки используются для разных сущностей, делать для каждой отдельную конфигурацию? И вообще не нарушение ли это того же single responsibility?
1) Вы можете использовать свой ViewController и вложить в него UITableViewController, как описано в статье. Если все-таки создать наследника и для UITableViewController, то для борьбы с дублирующимся кодом существует множество паттернов. В Swift для этогй цели можно использовать protocol extensions (к сожалению, не всегда). Но если ничего не помогает, то всегда есть первый вариант.
2) Ячейка конфигурируется не из модели, а из ячейки (с использованием модели). Ячейка проставляет значения для своих subviews – не вижу здесь нарушение single responsibility. Само собой, модель должна содержать данные в конечной форме (готовые к представлению), ячейка не должна заниматься парсингом и другими несвойственными ей операциями.
Sign up to leave a comment.

Articles