Разработка
Понимаем архитектуру VIPER
Существует множество шаблонов проектирования, таких как MVI, MVP, MVVM и т.д. Все они имеют свои преимущества и недостатки. В зависимости от размера вашего проекта, вы можете выбрать тот или другой. В этой статье я попытаюсь на примере объяснить шаблон проектирования VIPER. Также вы можете прочитать о других шаблонах проектирования архитектуры в другой моей статье здесь.
Прежде всего, я хочу немного рассказать о самомVIPER.
Что такое VIPER?
VIPER — это архитектура. Она снижает сложность, особенно в больших проектах. Целью архитектуры является разделение операционного кода внутри проекта, модуляризация и регуляризация. В основном она использует протоколы, поскольку межуровневая связь в шаблоне VIPER обеспечивается протоколами.
View
Это наш ViewController, и он отвечает за отображение данных пользователю. Здесь мы используем только данные от презентера. Никаких других действий не предпринимается.
Interactor
Можно сказать, что он действует как ViewModel в шаблоне проектирования MVVM. Это часть приложения, которое мы называем бизнес логикой. UI-операции здесь не выполняются. Здесь выполняются операции выборки, обновления, доступ к API и т.д.
Presenter
Это мост между View и Interactor. Этот уровень не должен содержать логических операций пользовательского интерфейса или бизнес-процессов.
Entity
Это модельная часть приложения. Модели данных, связанные с приложением, находятся здесь. Эта часть взаимодействует только с Interactor.
Router
Этот слой позволяет нам определить, когда отображаются страницы приложения. Маршрутизатор помогает связывать слои друг с другом. Мы описываем наши протоколы здесь.
Давайте посмотрим поближе. Я попытался объяснить VIPER с помощью простого iOS-приложения.
Пример VIPER
Во-первых, мы сделаем наше представление. Здесь вы можете увидеть кнопки операций, результат и текстовые поля ввода. Я использовал Storyboard, чтобы создать свое представление.
import UIKit | |
class ViewController: UIViewController { | |
@IBOutlet weak var txtFieldNumber2: UITextField! | |
@IBOutlet weak var txtFieldNumber1: UITextField! | |
@IBOutlet weak var labelResult: UILabel! | |
var presenterObj: ViewToPresenterProtocol? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
labelResult.text = "0" | |
Router.createModule(ref: self) | |
} | |
@IBAction func btnAdd(_ sender: Any) { | |
if let number1 = txtFieldNumber1.text, let number2 = txtFieldNumber2.text { | |
presenterObj?.addition(num1: number1, num2: number2) | |
} | |
} | |
@IBAction func btnMultiply(_ sender: Any) { | |
if let number1 = txtFieldNumber1.text, let number2 = txtFieldNumber2.text { | |
presenterObj?.multiplication(num1: number1, num2: number2) | |
} | |
} | |
} | |
extension ViewController: PresenterToViewProtocol { | |
func sendDataToView(result: String) { | |
labelResult.text = result | |
} | |
} |
Протоколы являются важной частью в этой архитектуре. Я рассмотрю протоколы под двумя разными названиями: протоколы связи (carrier) и основные протоколы (main).
В этом приложении InteractorToPresenterProtocol и PresenterToViewProtocol являются нашими протоколами связи. Эти протоколы помогают нам переносить финальные данные, сформированные в интеракторе, от презентера к представлению. Вот почему мы назвали их InteractorToPresenter и PresenterToView.
ViewToPresenterProtocol и PresenterToInteractorProtocol являются основными протоколами, они включают в себя не только функции, но и свойства. Мы используем эти протоколы для отправки данных из представления в интерактор через презентер.
import Foundation | |
protocol InteractorToPresenterProtocol { | |
func sendDataToPresenter(result: String) | |
} | |
protocol PresenterToViewProtocol { | |
func sendDataToView(result: String) | |
} | |
protocol ViewToPresenterProtocol { | |
var view: PresenterToViewProtocol? { get set } | |
var interactor: PresenterToInteractorProtocol? { get set } | |
func addition(num1: String, num2: String) | |
func multiplication(num1: String, num2: String) | |
} | |
protocol PresenterToInteractorProtocol { | |
var presenter: InteractorToPresenterProtocol? { get set} | |
func add(num1: String, num2: String) | |
func multiply(num1: String, num2: String) | |
} | |
protocol PresenterToRouterProtocol { | |
static func createModule(ref: ViewController) | |
} |
Нет необходимости определять переменные в протоколах связи. Они несут данные с помощью методов. Однако в основных протоколах нам нужно тригерить данные, определяя переменные.
Обратите внимание, что в тригерном классе должен быть объект из сработавшего класса.
Теперь мы создадим другие элементы VIPER: интерактор и презентер.
import Foundation | |
class Interactor: PresenterToInteractorProtocol { | |
var presenter: InteractorToPresenterProtocol? | |
func add(num1: String, num2: String) { | |
if let s1 = Int(num1), let s2 = Int(num2) { | |
let sum = s1 + s2 | |
presenter?.sendDataToPresenter(result: String(sum)) | |
} | |
} | |
func multiply(num1: String, num2: String) { | |
if let s1 = Int(num1), let s2 = Int(num2) { | |
let mul = s1 * s2 | |
presenter?.sendDataToPresenter(result: String(mul)) | |
} | |
} | |
} |
import Foundation | |
class Presenter: ViewToPresenterProtocol { | |
var view: PresenterToViewProtocol? | |
var interactor: PresenterToInteractorProtocol? | |
func addition(num1: String, num2: String) { | |
interactor?.add(num1: num1, num2: num2) | |
} | |
func multiplication(num1: String, num2: String) { | |
interactor?.multiply(num1: num1, num2: num2) | |
} | |
} | |
extension Presenter: InteractorToPresenterProtocol { | |
func sendDataToPresenter(result: String) { | |
view?.sendDataToView(result: result) | |
} | |
} |
В роутере делаем авторизацию, позволяющую работать всем протоколам.
import Foundation | |
class Router: PresenterToRouterProtocol { | |
static func createModule(ref: ViewController) { | |
let presenter = Presenter() | |
ref.presenterObj = presenter | |
ref.presenterObj?.interactor = Interactor() | |
ref.presenterObj?.view = ref | |
ref.presenterObj?.interactor?.presenter = presenter | |
} | |
} |
Обратите внимание, что у этой архитектуры также есть свои недостатки, такие как сложность ее использования в небольших проектах и большое количества папок и делегатов в проекте.
Но в целом мы завершили наше базовое приложение для iOS, используя шаблон проектирования VIPER. Вы можете получить доступ ко всему коду здесь.
Я надеюсь, что это было достаточно просто для вас, чтобы понять шаблон проектирования VIPER.
Еще про VIPER
- Viperit: шаблон для VIPER
- Мобильные архитектуры
- Разбор архитектуры VIPER на примере небольшого iOS приложения на Swift 4
- Начало работы с архитектурным шаблоном VIPER
- Шаблоны проектирования MVC, MVP, MVI, MVVM и VIPER
- VIPER и SwiftUI: Model layer
- Понимаем архитектуры iOS-приложений с помощью VIPER
- Как реализовать архитектуру VIPER в iOS-приложении с помощью Swift 5
- Что мы узнали, переключившись с MVC на VIPER
-
Новости4 недели назад
Видео и подкасты о мобильной разработке 2025.11
-
Новости1 неделя назад
Видео и подкасты о мобильной разработке 2025.14
-
Видео и подкасты для разработчиков3 недели назад
Javascript для бэкенда – отличная идея: Node.js, NPM, Typescript
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.12