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 기반 프로그래밍의 개념과 활용 방법을 상세히 설명하고 다양한 예제를 제공했습니다.