VIPER 기초
사내 iOS 앱은 최초 VIPER 패턴으로 작업되어 있었다. RxSwift을 조금더 쉽게 적용하기 위해서 MVVM 패턴으로 리팩토링 하는 과정에서 내가 입사하게 되었고, VIPER 패턴과 MVVM 패턴을 모두 알아야 각각 화면 작업과 동시에 리팩토링 작업도 할 수 있기 때문에 그 중 VIPER패턴을 조금 더 공부하고자 포스팅하게 되었다.
VIPER패턴
- View, Interactor, Presenter, Entity, Router로 구성되며 단일책임원칙 기반 아키텍쳐이다.
- 각각 파일분리가 많아진 만큼이나, 역할이 명확하다.
View
- UIViewController, View들 그 자체이다. 사용자의 액션에 반응하고, 보여주며 주로 Presenter와 상호작용한다.
protocol ToDoView: AnyObject {
func showToDoItems(_ items: [ToDoItem])
}
class ToDoViewController: UIViewController, ToDoView {
var presenter: ToDoPresentation?
private var items: [ToDoItem] = []
override func viewDidLoad() {
super.viewDidLoad()
presenter?.viewDidLoad()
}
func showToDoItems(_ items: [ToDoItem]) {
self.items = items
// Update the UI, e.g., reload a table view
}
}Interactor
- 데이터 또는 네트워크와 관련된 비즈니스 로직을 가지고 있는 단위로, 주로 API Fetch, DataRepository와 같이 데이터 로직을 가지고 있는 모듈이다. 뷰와 완전히 독립되어야 한다.
protocol ToDoInteractorInput: AnyObject {
func fetchToDoItems()
}
protocol ToDoInteractorOutput: AnyObject {
func didFetchToDoItems(_ items: [ToDoItem])
}
class ToDoInteractor: ToDoInteractorInput {
weak var output: ToDoInteractorOutput?
func fetchToDoItems() {
let items = [ToDoItem(title: "Sample Task 1"), ToDoItem(title: "Sample Task 2")]
output?.didFetchToDoItems(items)
}
}Presenter
- UI 관련 비즈니스 로직을 포함하며, View의 사용자 액션을 받아, Interactor로 전달하며, Interactor로부터 데이터를 전달 받아 View를 Update하는 로직을 가지고 있다.
protocol ToDoPresentation: AnyObject {
func viewDidLoad()
}
class ToDoPresenter: ToDoPresentation {
weak var view: ToDoView?
var interactor: ToDoInteractorInput?
var router: ToDoWireframe?
func viewDidLoad() {
interactor?.fetchToDoItems()
}
}
extension ToDoPresenter: ToDoInteractorOutput {
func didFetchToDoItems(_ items: [ToDoItem]) {
view?.showToDoItems(items)
}
}
Entities
- 일반적인 데이터 객체들, 데이터 모델
struct ToDoItem {
let title: String
}Router
- WireFrame으로도 불리며, 화면이 언제 표시되어야 하는지, 어떤화면을 어디에 띄울것인지를 결정한다, (Navigation 의 역할을 한다)
protocol ToDoWireframe: AnyObject {
static func createModule() -> UIViewController
}
class ToDoRouter: ToDoWireframe {
static func createModule() -> UIViewController {
let view = ToDoViewController()
let presenter = ToDoPresenter()
let interactor = ToDoInteractor()
let router = ToDoRouter()
view.presenter = presenter
presenter.view = view
presenter.interactor = interactor
presenter.router = router
interactor.output = presenter
return view
}
}MVVM만 접해본 상태에서의 VIPER 패턴의 첫 인상은 복잡하다 였다. 각각의 역할이 구분되었기 때문에 testable하다는 장점이 있지만, 간단한 화면을 만들 때에는 오히려 오버스펙이지 않을까 생각이 되었다.