저는 SwiftUI로 iOS 개발을 공부해왔습니다.
@State, @Binding, @ObservedObject… 이런 키워드만 있으면 데이터가 바뀌면 UI가 저절로 바뀌는, 말 그대로 마법 같은 환경이 익숙했지만 UIKit으로 넘어오면서 MVVM 패턴을 적용해보려던 순간, 나는 **클로저(Closure)**라는 녀석과 마주쳐 어떠한 역할을 하는지 알아보려고 합니다.
SwiftUI에서는 왜 클로저를 안 썼지?
SwiftUI에서는 데이터에 @Published만 붙여주면 UI는 알아서 반응한다.
class ViewModel: ObservableObject {
@Published var title = "Hello"
}
struct MyView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Text(viewModel.title) // 자동 업데이트
}
}
이런 게 너무 당연하다고 생각했고,
"데이터 바뀌면 화면도 바뀌는 게 그냥 기본 아니야?" 라고 생각했었다.
하지만 UIKit은 다르다 !
UIKit에서는 똑같이 ViewModel을 만들어도, 값이 바뀌었다고 해서 UI가 자동으로 바뀌지 않는다.
그래서 ViewModel에서는 값이 바뀌었을 때,
ViewController에 '값이 바뀌었어!'라고 알려줘야 한다.
바로 이때 사용하는 게 클로저였다.
UIKit MVVM에서 클로저가 하는 역할
var titleChanged: ((String) -> Void)?
이렇게 ViewModel에 선언해두고, 값이 바뀔 때 직접 호출해야 한다.
var title: String = "" {
didSet {
titleChanged?(title)
}
}
그리고 ViewController에서는 이렇게 바인딩해야 한다.
viewModel.titleChanged = { [weak self] newTitle in
self?.titleLabel.text = newTitle
}
SwiftUI에서는 @Published 한 줄이면 되는 걸,
UIKit에서는 이렇게 클로저로 직접 수동 연결해야 한다는 게 처음엔 낯설었다.
클로저를 옵셔널로 쓰는 이유?
이것도 처음엔 궁금했다.
그런데 생각해보면 ViewModel이 먼저 생성되고, ViewController가 나중에 클로저를 바인딩하기 때문에
초기에는 nil일 수밖에 없다.
그래서 항상 titleChanged?() 처럼 옵셔널 체이닝으로 안전하게 호출해야 한다는 걸 알게 됐다.
공식 문서 – Swift Optional Chaining
내가 실제로 작성한 ViewModel 예시
final class OrderViewModel {
var categoryChanged: (() -> Void)?
private(set) var selectedCategory: Category = .coffee {
didSet {
categoryChanged?()
}
}
func changeCategory(_ category: Category) {
selectedCategory = category
}
}
이렇게 하면 ViewModel이 ViewController를 전혀 몰라도
카테고리가 바뀔 때 View에 알릴 수 있었다.
SwiftUI와 UIKit MVVM 정리
비교 항목 | SwiftUI | UIKit |
값 변경 시 UI 업데이트 | 자동 (`@Published`) | 직접 알림 (클로저) |
데이터 흐름 | 단방향 바인딩 | 수동 트리거 |
클로저 사용 여부 | 거의 없음 | 필수 |
ViewModel ↔ View 연결 방식 | 선언만 하면 연결됨 | 클로저 바인딩 필요 |
공식 문서 – Swift Closures
마무리하며
처음엔 "왜 이렇게 복잡하지?" 싶었지만,
지금은 UIKit MVVM에서 클로저가 얼마나 강력한 도구인지 이해하게 되었다.
ViewModel은 View를 전혀 몰라도 되고, View는 ViewModel의 이벤트만 처리하면 되니까
책임 분리(Separation of Concerns) 측면에서 정말 깔끔하다.
SwiftUI 덕분에 편하게 시작했지만,
UIKit을 하면서 더 저수준의 연결 구조를 이해하게 된 것 같다.
'iOS > UIKit' 카테고리의 다른 글
[ UIKit ] UITableViewCell에서 AutoLayout 충돌 이슈 해결 (0) | 2025.04.16 |
---|---|
[UIKit] ViewController의 개념과 생명주기 정리 (0) | 2025.04.14 |
[ UIKit ] Combine으로 상태를 바인딩하는 방법 (0) | 2025.04.06 |
[ UIKit ] Delegate 패턴 알아보기 (0) | 2025.04.06 |
[ UIKit ] UISlider (20) | 2024.02.03 |
저는 SwiftUI로 iOS 개발을 공부해왔습니다.
@State, @Binding, @ObservedObject… 이런 키워드만 있으면 데이터가 바뀌면 UI가 저절로 바뀌는, 말 그대로 마법 같은 환경이 익숙했지만 UIKit으로 넘어오면서 MVVM 패턴을 적용해보려던 순간, 나는 **클로저(Closure)**라는 녀석과 마주쳐 어떠한 역할을 하는지 알아보려고 합니다.
SwiftUI에서는 왜 클로저를 안 썼지?
SwiftUI에서는 데이터에 @Published만 붙여주면 UI는 알아서 반응한다.
class ViewModel: ObservableObject {
@Published var title = "Hello"
}
struct MyView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Text(viewModel.title) // 자동 업데이트
}
}
이런 게 너무 당연하다고 생각했고,
"데이터 바뀌면 화면도 바뀌는 게 그냥 기본 아니야?" 라고 생각했었다.
하지만 UIKit은 다르다 !
UIKit에서는 똑같이 ViewModel을 만들어도, 값이 바뀌었다고 해서 UI가 자동으로 바뀌지 않는다.
그래서 ViewModel에서는 값이 바뀌었을 때,
ViewController에 '값이 바뀌었어!'라고 알려줘야 한다.
바로 이때 사용하는 게 클로저였다.
UIKit MVVM에서 클로저가 하는 역할
var titleChanged: ((String) -> Void)?
이렇게 ViewModel에 선언해두고, 값이 바뀔 때 직접 호출해야 한다.
var title: String = "" {
didSet {
titleChanged?(title)
}
}
그리고 ViewController에서는 이렇게 바인딩해야 한다.
viewModel.titleChanged = { [weak self] newTitle in
self?.titleLabel.text = newTitle
}
SwiftUI에서는 @Published 한 줄이면 되는 걸,
UIKit에서는 이렇게 클로저로 직접 수동 연결해야 한다는 게 처음엔 낯설었다.
클로저를 옵셔널로 쓰는 이유?
이것도 처음엔 궁금했다.
그런데 생각해보면 ViewModel이 먼저 생성되고, ViewController가 나중에 클로저를 바인딩하기 때문에
초기에는 nil일 수밖에 없다.
그래서 항상 titleChanged?() 처럼 옵셔널 체이닝으로 안전하게 호출해야 한다는 걸 알게 됐다.
공식 문서 – Swift Optional Chaining
내가 실제로 작성한 ViewModel 예시
final class OrderViewModel {
var categoryChanged: (() -> Void)?
private(set) var selectedCategory: Category = .coffee {
didSet {
categoryChanged?()
}
}
func changeCategory(_ category: Category) {
selectedCategory = category
}
}
이렇게 하면 ViewModel이 ViewController를 전혀 몰라도
카테고리가 바뀔 때 View에 알릴 수 있었다.
SwiftUI와 UIKit MVVM 정리
비교 항목 | SwiftUI | UIKit |
값 변경 시 UI 업데이트 | 자동 (`@Published`) | 직접 알림 (클로저) |
데이터 흐름 | 단방향 바인딩 | 수동 트리거 |
클로저 사용 여부 | 거의 없음 | 필수 |
ViewModel ↔ View 연결 방식 | 선언만 하면 연결됨 | 클로저 바인딩 필요 |
공식 문서 – Swift Closures
마무리하며
처음엔 "왜 이렇게 복잡하지?" 싶었지만,
지금은 UIKit MVVM에서 클로저가 얼마나 강력한 도구인지 이해하게 되었다.
ViewModel은 View를 전혀 몰라도 되고, View는 ViewModel의 이벤트만 처리하면 되니까
책임 분리(Separation of Concerns) 측면에서 정말 깔끔하다.
SwiftUI 덕분에 편하게 시작했지만,
UIKit을 하면서 더 저수준의 연결 구조를 이해하게 된 것 같다.
'iOS > UIKit' 카테고리의 다른 글
[ UIKit ] UITableViewCell에서 AutoLayout 충돌 이슈 해결 (0) | 2025.04.16 |
---|---|
[UIKit] ViewController의 개념과 생명주기 정리 (0) | 2025.04.14 |
[ UIKit ] Combine으로 상태를 바인딩하는 방법 (0) | 2025.04.06 |
[ UIKit ] Delegate 패턴 알아보기 (0) | 2025.04.06 |
[ UIKit ] UISlider (20) | 2024.02.03 |