Post

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.