На сегодняшний день в iOS разработке существует очень много различных архитектур, и их количество постоянно увеличивается. Мы вкратце рассмотрим лишь самые популярные из них. Под архитектурой мы понимаем архитектурный шаблон проектирования, охватывающий все приложение или какую-то его часть. Часто такую часть называют модулем. Из этих модулей и строится приложение. Под модулями в данном случае понимаются не Swift-модули, а архитектурные модули. Им может являться, например, один экран приложения или несколько связанных между собой экранов. Тема архитектур вызывает много споров. Во-первых, у каждого разработчика свое представление о том, какой должна быть хорошая архитектура. Во-вторых, даже если взять какую-то конкретную архитектуру, то вы сможете найти несколько различающихся между собой реализаций. И третья причина заключается в том, что идеальной архитектуры не существует. У каждой из них есть преимущества и недостатки. Поэтому при обсуждении архитектурных подходов всегда есть за что поругать любое из решений. Первая архитектура, которую мы разберем, MVC. Мы сразу сталкиваемся с тем, что под одним названием могут скрываться разные подходы. В iOS-сообществе MVC называют архитектуру, предлагаемую Apple. Она отличается от классической MVC. Как и во многих других архитектурах, название — это аббревиатура. Каждая буква обозначает один из компонентов. Рассмотрим их по порядку. M — Model. Роль модели могут играть как простые классы или структуры, так и сложные сущности, запрашивающие информацию из базы данных или из сети. Модель не знает о существовании UI. Можно рассматривать ее как ядро приложения, которое можно переиспользовать с другим интерфейсом. Например, использовать одну и ту же модель для iOS и MacOS приложения. V — View. View — это представление, то, что пользователь видит и с чем взаимодействует. Ответственность View — это прорисовка себя на экране и реагирование на действия пользователя. Но оно не содержит логики и просто передает событие в контроллер. В качестве представления в iOS-приложениях используются UIView и его наследники: UIButton — кнопка, UILabel — текст, UITextField — поле ввода и так далее. Одну и ту же View можно использовать на разных экранах приложения или даже переместив в другие. C — Controller. Контроллер — это связующее звено между моделью и представлением. Его ответственность заключается в том, чтобы принимать действия пользователя от View, обрабатывать их в случае необходимости и обновлять модель, а при изменении модели обновлять View. Apple представляет базовый класс для контроллера — UIViewController, и несколько дочерних: UITabBarController — для представления со вкладками и UINavigationController — для навигации между контроллерами и другие. Так как контроллеры содержат логику, специфичную для приложения, то их сложно переиспользовать. Один контроллер не всегда соответствует одному экрану. Их можно вкладывать друг в друга, разбив таким образом большой контроллер на несколько маленьких. Например, UITabBarController является контейнером для нескольких контроллеров. При нажатии на вкладке он просто подменяет один на другой. MVC — хороший выбор для простого приложения. Это архитектура, понятная даже новичкам, и ее знает каждый iOS-разработчик. Однако есть одна проблема с реализацией MVC от Apple. Они наделили UIController обязанностью следить за жизненным циклом UIView, из-за этого они очень сильно связаны. В итоге контроллер содержит не только обработку модели, но и взаимодействие с View. На слайде вы видите схему, которая больше похожа на то, как выглядит MVC от Apple в реальности. Для решения этой проблемы во всех остальных архитектурах UIViewController считается частью View. В нем остается обработка жестов, анимации и прочие взаимодействия с View, а всю остальную логику переносят в другое место. Таким образом мы избегаем так называемого Massive View Controller. Еще одна важная проблема, которая решается таким образом, сложность тестирования. Если вы хотите проверить какую-то логику, находящуюся в UIViewController, то вам придется иметь дело с жизненным циклом View. Если же все, что связано с UIKit, изолировать от остального приложения, то это намного облегчит тестирование. Очевидным развитием MVC является MVP. Раз UIVewController — это часть View, то вместо него нужно добавить какую-то другую сущность, никак не связанную с UIKit. В результате получаем Presenter. Получившаяся схема очень похожа на MVC от Apple. Разница в том, что вся логика, не связанная с представлением, перемещается из UIViewController в Presenter. Обратите также внимание на то, что View, как и в MVC, пассивная. Presenter передает в нее данные, но сама она их не запрашивает, хотя обращение к Presenter не запрещено. Оно может происходить, например, для вызова обработчика нажатием на кнопку. MVVM очень похожа на MVP. Разница в том, что вместо Presenter в нем используется ViewModel. ViewModel хранит в себе состояние представления, например, текст на экране или значение поля для ввода. Но в отличие от MVP View сама берет данные для отображения. Это можно реализовать разными способами. Но часто используется Data Binding — это подход, при котором один объект следит за состоянием другого. То есть View будет следить за своим значением, хранящемся во ViewModel, и изменять свое отображение при его изменении. MVVM и MVP решают проблему большого контроллера и облегчают тестирование. Однако порог вхождения в проекты, написанные на них, намного выше. Особенно это касается MVVM с binding'ами, так как часто в таких проектах связывание данных используется не только между View и ViewModel. Такой код сложнее понять новичку, а еще сложнее отлаживать. VIPER — в этом подходе уже не три компонента, а пять. Сделано это для лучшего разделения обязанностей. Рассмотрим все компоненты по порядку. V (View) — это тот же самый компонент, что и раньше, UIViewController плюс UIView. P — Presenter. Он немного отличается от Presenter из MVP. Дело в том, что MVP и MVVM позволяют избежать MassiveViewController, но в них большое количество логики переносится в Presenter и ViewModel соответственно. Поэтому его обязанности разделили на две части. Первая осталась в Presenter — он отвечает за подготовку данных для представления, но остается независимым от UIKit. Пример такой подготовки — локальная фильтрация. I — Interactor, новый компонент. В него переместилась вторая половина логики из Presenter, а именно обращение к базе данных, запрос данных на сервере, создание новых экземпляров данных и так далее. И Entity — это данные. В отличие от моделей в прошлых архитектурах тут не содержится никакая логика. R — Router. В предыдущих подходах не было указано, кто ответственный за переходы между модулями. Это может быть, например, Presenter или какая-то отдельная сущность. VIPER предлагает решить эту проблему с помощью роутера. Он будет ответственен за создание следующего модуля и передачу необходимых ему данных. Такое разделение позволяет еще больше упростить тестирование и избежать появления больших классов. Но из-за большого количества сущностей возрастают накладные расходы. Для создания простого экрана с кнопкой и текстом вам придется создать много дополнительных классов. Частично решить проблему можно с помощью специальных генераторов — шаблонных модулей. Но в дальнейшем при внесении каких-либо изменений вам придется изменять все вручную. Ну и очевидно, что порог вхождения в VIPER проекта очень высокий. Такой подход подойдет только для большого и долгосрочного проекта, иначе затраты на поддержку большой кодовой базы себя не оправдывают. Мы несколько раз упоминали обращение к базам данных и к сети. Такие операции имеют много дополнительной логики: формирование запроса, обработка ошибок, парсинг данных и так далее. Дублировать эту логику в каждом интеракторе неэффективно. Поэтому ее выносят в отдельный слой приложения, называемый сервисным. Он не упоминается в описании архитектур, так как его можно и нужно использовать в любой из них. Таким образом, любой модуль может получать необходимые ему данные. На этом наша лекция окончена. Ни одна архитектура не является лучшей. Если вашему проекту не подходит классическое решение, придумайте свое. Не забывайте, что архитектуры, как и любой другой инструмент, должны помогать создавать и поддерживать качественный продукт, а не создавать ненужные помехи. [БЕЗ_ЗВУКА]