MVVM (Model-View-ViewModel) 패턴
MVVM 패턴 소개 (Introduction to MVVM Pattern)
MVVM (Model-View-ViewModel) 패턴은 UI의 로직과 데이터 처리를 분리하여 코드의 유지보수성과 테스트 용이성을 향상시키는 디자인 패턴입니다. 이 패턴은 세 가지 주요 구성 요소로 이루어져 있습니다:
- Model: 애플리케이션의 데이터와 비즈니스 로직을 포함합니다. 데이터베이스와의 상호작용, 네트워크 요청 등의 기능을 담당합니다.
- View: 사용자 인터페이스(UI) 요소를 정의하며, 사용자와의 상호작용을 처리합니다. View는 ViewModel을 통해 데이터를 표시하고 사용자 입력을 전달합니다.
- ViewModel: View와 Model 사이의 중간자 역할을 하며, View에서 사용할 수 있는 데이터와 명령을 제공합니다. ViewModel은 Model로부터 데이터를 가져오고, 이를 가공하여 View에 전달합니다.
MVVM 패턴의 구조 (Structure of MVVM Pattern)
- Model: 데이터와 비즈니스 로직을 정의합니다.
// Model
struct User {
var name: String
var age: Int
}
- ViewModel: Model 데이터를 가공하고 View와의 바인딩을 처리합니다.
import Combine
// ViewModel
class UserViewModel: ObservableObject {
@Published var userName: String = ""
@Published var userAge: String = ""
private var user: User?
func loadUser() {
// 예시 데이터
self.user = User(name: "Alice", age: 30)
updateViewModel()
}
private func updateViewModel() {
guard let user = user else { return }
userName = user.name
userAge = "\(user.age)"
}
}
- View: UI를 정의하고 ViewModel을 바인딩합니다.
import SwiftUI
// View
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
VStack {
Text("Name: \(viewModel.userName)")
Text("Age: \(viewModel.userAge)")
}
.onAppear {
viewModel.loadUser()
}
}
}
MVVM 패턴의 예제 (MVVM Example)
이제 MVVM 패턴을 적용하여 SwiftUI에서 간단한 사용자 정보를 표시하는 예제를 작성합니다.
import SwiftUI
import Combine
// Model
struct User {
var name: String
var age: Int
}
// ViewModel
class UserViewModel: ObservableObject {
@Published var userName: String = ""
@Published var userAge: String = ""
private var user: User?
func loadUser() {
// 예시 데이터
self.user = User(name: "Alice", age: 30)
updateViewModel()
}
private func updateViewModel() {
guard let user = user else { return }
userName = user.name
userAge = "\(user.age)"
}
}
// View
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
VStack {
Text("Name: \(viewModel.userName)")
Text("Age: \(viewModel.userAge)")
}
.onAppear {
viewModel.loadUser()
}
}
}
// Preview
struct UserView_Previews: PreviewProvider {
static var previews: some View {
UserView()
}
}
Delegate 및 Closure 기반 프로그래밍
Delegate 패턴 소개 (Introduction to Delegate Pattern)
Delegate 패턴은 객체 간의 통신을 위해 사용되며, 한 객체가 다른 객체의 이벤트나 상태 변화를 전달받을 수 있도록 합니다. 주로 콜백 메서드를 통해 상호작용합니다. Delegate는 주로 protocol을 사용하여 정의합니다.
Delegate 패턴의 구조 (Structure of Delegate Pattern)
- Delegate Protocol: 이벤트나 상태 변화를 전달받기 위한 메서드를 정의합니다.
protocol DataDelegate: AnyObject {
func didReceiveData(_ data: String)
}
- Delegate 객체: 데이터를 제공하는 객체에서 delegate 프로퍼티를 통해 delegate 객체를 설정하고, 이벤트 발생 시 delegate 메서드를 호출합니다.
class DataProvider {
weak var delegate: DataDelegate?
func fetchData() {
// 데이터를 가져온 후
let data = "Sample Data"
delegate?.didReceiveData(data)
}
}
- Delegate 구현 객체: delegate 프로토콜을 채택하여 메서드를 구현합니다.
class DataReceiver: DataDelegate {
func didReceiveData(_ data: String) {
print("Received data: \(data)")
}
}
- Delegate 설정: delegate를 설정하고 데이터를 요청합니다.
let provider = DataProvider() let receiver = DataReceiver() provider.delegate = receiver provider.fetchData() // "Received data: Sample Data"
Closure 기반 프로그래밍 소개 (Introduction to Closure-based Programming)
Closure는 코드 블록을 변수처럼 다룰 수 있는 기능으로, 함수나 메서드 내에서 사용할 수 있습니다. Closure를 사용하면 함수 호출 시 동작을 커스터마이즈하거나 콜백을 구현할 수 있습니다.
Closure의 예제 (Example of Closures)
- 기본 클로저 사용: 함수에 클로저를 인자로 전달하여 실행할 수 있습니다.
func performOperation(_ operation: () -> Void) {
// 클로저 호출
operation()
}
performOperation {
print("Operation performed")
}
// "Operation performed"
- 클로저와 인자: 클로저를 사용하여 인자를 받아서 처리할 수 있습니다.
func calculate(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
let sum = calculate(a: 5, b: 3) { $0 + $1 }
print(sum) // 8
- 클로저 캡처링: 클로저는 자신이 정의된 환경을 캡처할 수 있습니다.
func makeIncrementer(incrementAmount: Int) -> () -> Int {
var total = 0
return {
total += incrementAmount
return total
}
}
let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo()) // 2
print(incrementByTwo()) // 4
- escaping 클로저: 클로저가 함수의 실행이 끝난 후에도 실행될 수 있도록 허용합니다.
func fetchData(completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
// 비동기 작업 시뮬레이션
sleep(2)
completion("Data fetched")
}
}
fetchData { result in
print(result) // "Data fetched"
}
이와 같이 Swift에서 MVVM 패턴, Delegate 패턴, 그리고 Closure 기반 프로그래밍의 개념과 활용 방법을 상세히 설명하고 다양한 예제를 제공했습니다.
