MVVM이란
MVVM이란
MVVM 아키텍처란? iOS 개발자가 알아야 할 구조와 실제 적용법
MVVM이란?
MVVM은 Model-View-ViewModel의 약자로, UI 코드와 비즈니스 로직을 분리하는 아키텍처 패턴이다.
- Model: 데이터 구조, 비즈니스 로직, 네트워크 요청 등 실제 동작을 담당한다.
- View: 화면(UI)만 담당한다. 뷰의 생명주기와 사용자 이벤트 처리 중심.
- ViewModel: Model과 View 사이에서 데이터를 가공하고 바인딩 로직을 처리한다.
왜 MVVM을 쓰는가?
1. 역할 분리로 유지보수 용이
- View는 화면 구성만, Model은 로직만 담당
- ViewModel이 중간에서 가공 로직을 분리해준다
2. 테스트 코드 작성이 쉬워짐
- ViewModel은 UIKit에 의존하지 않기 때문에 단위 테스트 가능
3. 재사용성과 확장성 증가
- ViewModel은 여러 View에서 재사용 가능
MVVM 흐름도
1
2
3
4
5
User Action → View → ViewModel → Model
↑ ↓
데이터 가공 및 전달
예제 (Swift + MVVM)
목표: 사용자 이름을 입력하면 인사말을 출력하는 화면
Model
1
2
3
struct User {
let name: String
}
ViewModel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import Foundation
class GreetingViewModel {
private var user: User?
// Output
var greetingText: ((String) -> Void)?
// Input
func didTapGreetButton(with name: String) {
user = User(name: name)
let message = "안녕하세요, \(user?.name ?? "")님"
greetingText?(message)
}
}
ViewController (View)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import UIKit
class GreetingViewController: UIViewController {
let viewModel = GreetingViewModel()
let nameField = UITextField()
let greetButton = UIButton()
let resultLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.greetingText = { [weak self] text in
DispatchQueue.main.async {
self?.resultLabel.text = text
}
}
greetButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
}
@objc func didTapButton() {
let name = nameField.text ?? ""
viewModel.didTapGreetButton(with: name)
}
}
ViewModel에 로직을 넣는 기준
다음과 같은 처리는 ViewModel에 넣는다.
- 데이터 가공 (
숫자 포맷
,날짜 처리
,UI 출력 문자열 만들기
) - 모델 → 뷰 데이터 변환 (
DTO → ViewData
) - 로딩 상태 관리
- 입력 검증
반대로 다음은 View에 남긴다.
- UI 레이아웃 처리 (AutoLayout, SwiftUI View 등)
- 뷰 생명주기 (
viewDidLoad
,onAppear
등)
RxSwift, Combine, SwiftUI와 MVVM
- RxSwift나 Combine을 쓰면 ViewModel → View 바인딩이 깔끔해진다
- SwiftUI는 MVVM과 거의 궁합이 맞는 구조 (State, Binding, ObservableObject 활용)
@Published
,@ObservedObject
,@StateObject
등으로 뷰 갱신 처리 가능
MVVM의 단점도 존재한다
- 작은 화면에까지 MVVM을 적용하면 오히려 과한 분리로 코드 복잡도만 올라간다
- ViewModel이 지나치게 비대해지기 쉬움 (→ use case 분리로 해결 가능)
- UI 이벤트가 많은 화면은 MVVM만으로 관리가 어려움 (→ Reactor, MVI 등 고려)
마무리
MVVM은 뷰와 로직을 자연스럽게 분리할 수 있는 실용적인 구조다. SwiftUI, RxSwift와도 잘 어울리고, 테스트 코드 작성도 용이하다. 단, 모든 화면에 무조건 적용할 필요는 없고 **“분리할 이유가 있을 때만 적용”**하는 게 실전이다.
- 재사용성 필요할 때
- 테스트 코드 작성이 중요한 컴포넌트
- 복잡한 데이터 가공이 있을 때
이럴 땐 적극적으로 ViewModel로 분리해보는 걸 추천한다.
```
This post is licensed under CC BY 4.0 by the author.