Ответ
VIPER — это архитектурный паттерн, разделяющий ответственность на пять компонентов: View, Interactor, Presenter, Entity, Router. Он обеспечивает высокую тестируемость и разделение модулей.
Пример: Модуль входа в систему (Login)
-
Entity (Модель данных)
struct User { let email: String } // Entity — это простые структуры данных, без логики. -
Interactor (Бизнес-логика)
protocol LoginInteractorInputProtocol: AnyObject { func loginUser(email: String, password: String) }
protocol LoginInteractorOutputProtocol: AnyObject { func loginDidSucceed(user: User) func loginDidFail(error: Error) }
final class LoginInteractor: LoginInteractorInputProtocol { weak var presenter: LoginInteractorOutputProtocol? private let authService: AuthServiceProtocol // Зависимость для работы с сетью/БД
func loginUser(email: String, password: String) {
authService.login(email: email, password: password) { [weak self] result in
switch result {
case .success(let user):
self?.presenter?.loginDidSucceed(user: user)
case .failure(let error):
self?.presenter?.loginDidFail(error: error)
}
}
}
}
3. **Presenter (Логика представления)**
```swift
protocol LoginPresenterProtocol: AnyObject {
func viewDidLoad()
func didTapLoginButton(email: String?, password: String?)
}
final class LoginPresenter: LoginPresenterProtocol {
weak var view: LoginViewProtocol?
var interactor: LoginInteractorInputProtocol?
var router: LoginRouterProtocol?
func didTapLoginButton(email: String?, password: String?) {
guard let email = email, let password = password, !email.isEmpty, !password.isEmpty else {
view?.showValidationError()
return
}
view?.showLoadingIndicator(true)
interactor?.loginUser(email: email, password: password)
}
}
// Presenter также реализует протокол вывода Interactor'а
extension LoginPresenter: LoginInteractorOutputProtocol {
func loginDidSucceed(user: User) {
view?.showLoadingIndicator(false)
router?.routeToHomeScreen(with: user)
}
func loginDidFail(error: Error) {
view?.showLoadingIndicator(false)
view?.showError(message: error.localizedDescription)
}
}
- View (Отображение)
protocol LoginViewProtocol: AnyObject { func showLoadingIndicator(_ show: Bool) func showError(message: String) func showValidationError() }
final class LoginViewController: UIViewController, LoginViewProtocol { var presenter: LoginPresenterProtocol! @IBOutlet private weak var emailTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
presenter.viewDidLoad()
}
@IBAction private func loginButtonTapped() {
presenter.didTapLoginButton(email: emailTextField.text, password: "...")
}
// MARK: - LoginViewProtocol
func showError(message: String) {
let alert = UIAlertController(title: "Ошибка", message: message, preferredStyle: .alert)
present(alert, animated: true)
}
// ... остальные методы протокола
}
5. **Router (Навигация)**
```swift
protocol LoginRouterProtocol: AnyObject {
func routeToHomeScreen(with user: User)
}
final class LoginRouter: LoginRouterProtocol {
weak var viewController: UIViewController?
func routeToHomeScreen(with user: User) {
let homeVC = HomeModuleBuilder.build(with: user)
viewController?.navigationController?.pushViewController(homeVC, animated: true)
}
}
Сборка модуля (Assembly/Builder):
enum LoginModuleBuilder {
static func build() -> UIViewController {
let view = LoginViewController()
let presenter = LoginPresenter()
let interactor = LoginInteractor()
let router = LoginRouter()
view.presenter = presenter
presenter.view = view
presenter.interactor = interactor
presenter.router = router
interactor.presenter = presenter
router.viewController = view
return view
}
}
Преимущества VIPER: Четкое разделение ответственности, высокая тестируемость каждого компонента изолированно, удобство поддержки больших проектов.