MVVM 패턴
뷰, 뷰 모델, 모델의 역할을 분리합니다.
MVVM 패턴은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
MVVM이란 무엇인가요
MVVM은 Model-View-ViewModel을 의미합니다. 앱을 세 개의 계층으로 나누는 아키텍처 패턴이며, 각 계층에는 명확한 단일 책임이 있습니다.
- 모델 — 데이터와 비즈니스 규칙
- 뷰 — 사용자가 보는 화면
- ViewModel — 모델 데이터를 뷰에 맞게 준비하는 연결 계층
목표는 관심사 분리입니다. 각 계층이 다른 계층과 독립적으로 자신만의 이유에 따라 변경됩니다.
모델 계층
모델은 원시 데이터와 이를 관리하는 규칙을 보유합니다. 화면이나 항목이 표시되는 방식에 대해서는 알지 못합니다.
모델은 일반적으로 단순한 구조체나 도메인 객체입니다. UI 의존성이 없기 때문에 쉽게 테스트할 수 있습니다.
struct User {
let id: UUID
let firstName: String
let lastName: String
let isPremium: Bool
}
struct Order {
let items: [String]
let total: Decimal
}뷰 계층
뷰는 표현만 담당합니다. SwiftUI에서는 View 구조체이고, UIKit에서는 UIViewController와 그 하위 뷰입니다.
좋은 뷰에는 비즈니스 로직이 없어야 합니다. 상태를 렌더링하고 사용자의 동작을 ViewModel에 전달하기만 합니다.
struct ProfileView: View {
@StateObject var viewModel: ProfileViewModel
var body: some View {
VStack {
Text(viewModel.displayName)
if viewModel.showBadge {
Text("Premium")
}
}
}
}ViewModel 계층
ViewModel은 모델과 뷰 사이에 위치합니다. 원시 모델 데이터를 가져와 뷰가 바로 표시할 수 있는 표시용 값으로 변환합니다.
또한 사용자의 상호작용이 발생했을 때 뷰가 호출하는 의도(메서드)를 제공합니다.
final class ProfileViewModel: ObservableObject {
@Published var displayName: String
@Published var showBadge: Bool
init(user: User) {
displayName = user.firstName + " " + user.lastName
showBadge = user.isPremium
}
}관심사를 분리하는 이유
서식 지정, 네트워킹, 렌더링이 모두 뷰 컨트롤러 안에 뒤섞이면 해당 파일은 거대하고 테스트하기 어려운 덩어리가 됩니다.
책임을 나누면 다음과 같은 장점이 있습니다.
- 모델을 여러 화면에서 재사용할 수 있습니다.
- UI 없이도 ViewModel을 단위 테스트할 수 있습니다.
- 뷰를 작고 선언적으로 유지할 수 있습니다.
모델에 포함할 내용
다음 항목을 모델에 넣습니다.
- 도메인 엔터티(
User,Product) - 비즈니스 검증 규칙
- 영속성 및 네트워킹 추상화(대개 ViewModel이 호출하는 서비스를 통해 제공)
UI 문자열, 색상 또는 서식은 모델에 절대 넣지 않습니다.
ViewModel에 포함할 내용
ViewModel은 표현 로직을 처리합니다.
- 날짜, 통화, 이름을 표시 문자열로 서식 지정하기
- 표시할 UI 상태 결정하기(로딩, 오류, 비어 있음)
- 서비스 호출을 조정하고 결과 제공하기
final class CartViewModel: ObservableObject {
@Published var totalText: String = ""
func update(with order: Order) {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
totalText = formatter.string(from: order.total as NSNumber) ?? "-"
}
}뷰에 포함할 내용
뷰는 다음 작업만 해야 합니다.
- UI 요소 배치 및 렌더링
- ViewModel에서 게시된 상태 읽기
- ViewModel 메서드를 호출해 탭과 제스처 전달하기
뷰 안에 비즈니스 규칙을 결정하는 if가 있다면, 해당 로직은 ViewModel에 속할 가능성이 높습니다.
MVVM의 데이터 흐름
데이터는 한 방향으로 흐르고, 동작은 반대 방향으로 흐릅니다.
- 데이터: 모델 -> ViewModel -> 뷰
- 사용자 의도: 뷰 -> ViewModel
뷰는 모델과 직접 통신하지 않습니다. 따라서 의존성이 도메인을 향해 안쪽으로 향하도록 유지할 수 있습니다.
MVVM과 MVC 비교
전통적인 MVC에서는 컨트롤러가 서식 지정, 네트워킹, 뷰 연결을 한꺼번에 담당하기 때문에 규모가 지나치게 커지는 경우가 많습니다.
MVVM은 이러한 표현 로직을 ViewModel로 분리해 컨트롤러(또는 SwiftUI 뷰)를 얇게 유지합니다. ViewModel은 UI 프레임워크와 무관하므로 훨씬 쉽게 테스트할 수 있습니다.
완전한 구성 예시
다음은 계층을 하나로 연결한 작지만 완전한 MVVM 구성 예시입니다.
struct Account { let balance: Decimal }
final class AccountViewModel: ObservableObject {
@Published var balanceText: String
init(account: Account) {
balanceText = "$" + "\(account.balance)"
}
}
struct AccountView: View {
@StateObject var viewModel: AccountViewModel
var body: some View { Text(viewModel.balanceText) }
}빠른 확인
MVVM의 책임에 대한 이해도를 확인해 보세요.
복습
MVVM의 세 계층과 각 계층의 경계를 배웠습니다.
- 모델 — UI를 제외한 원시 데이터와 비즈니스 규칙
- ViewModel — 표현 로직과 사용자 의도
- 뷰 — ViewModel 상태를 순수하게 렌더링
이러한 관심사를 분리하면 코드를 테스트하고 재사용하기 쉬우며 이해하기도 쉬워집니다. 다음에는 바인딩을 사용해 ViewModel을 뷰에 연결합니다.
자주 묻는 질문
“MVVM 패턴” 강의는 무료인가요?
네 — “MVVM 패턴” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“MVVM 패턴”에서 뭘 배우나요?
뷰, 뷰 모델, 모델의 역할을 분리합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Swift Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“MVVM 패턴” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.