- SwiftUI는 Apple 앱을 개발하는 완전히 새로운 방식입니다.
- 이번에는 SwiftUI에서의 데이터 흐름과 라이프사이클을 알아보고자 합니다.
- SwiftUI 데이터 흐름에 대해서는 애플의 WWDC19와 WWDC20 영상이 있습니다.
- SwiftUI 데이터 흐름에 대한 애플의 공식 문서도 존재합니다.
SwiftUI 라이프사이클
- SwiftUI에는 View의 상태를 나타내는 함수가 즉, 라이프사이클이 아래와 같이 단 두가지 밖에 없습니다.
- 대신 상태를 나타내는 다양한 Property Wrapper가 존재해 Data 흐름에 대한 여러 상태에 대응할 수 있습니다.
.onAppear {
print("View appeared")
}
.onDisappear {
print("View disappeared")
}
@State
- 일반적으로 struct는 값 타입이여서 struct내의 값을 변경할 수 없습니다.
- SwiftUI는
@State
를 제공해 struct내의 값을 변경할 수 있게 해줍니다.
struct ContentView: View {
@State private var number = 0
}
- SwiftUI의 view는 struct이고, 이는 언제든 소멸되거나 재생성됩니다.
- 그렇기 때문에
@State
를 사용해 지속적으로 변형 가능한 변수를 만드는 것입니다. - 단,
@State
는 String, Int, Bool과 같은 간단한 타입에만 사용되는 것이 좋습니다. - 일반적으로
@State
변수는 private으로 선언되고, 다른 view와 공유되지 않습니다. - 다른 view와 값을 공유하고 싶다면, @StateObject나 @ObservedObject를 사용하면 됩니다.
@Binding
@Binding
은 부모 view의 @State
와 같은 값을 양방향으로 연결되도록 해줍니다.- 아래 코드에서
isPresented
는 showAddView
를 바인딩 시켜줘서 값을 변경해줍니다.
struct ContentView: View {
@State private var showAddView = false
var body: some View {
VStack {
Text("Hello World.")
}
}
.sheet(isPresented: $showAddView) {
AddView(isPresented: self.$showAddView)
}
}
struct AddView: View {
@Binding var isPresented: Bool
var body: some View {
Button("Dismiss") {
self.isPresented = false
}
}
}
ObservableObject
- ObservableObject는 Protocol으로 Combine 프레임워크의 일부입니다.
- 이것을 사용하기 위해서는, Protocol을 준수하고
@Published
를 사용하면 됩니다. @Published
를 사용하면 변수의 값이 추가되거나 삭제 되었다는 것을 View가 알 수 있게 해줍니다.- ObservableObject는 MVVM 아키텍쳐의 ViewModel에 적용하기 좋은 프로토콜입니다.
class MyViewModel: ObservableObject {
@Published var dataSource: MyModel
init(dataSource: MyModel) {
self.dataSource = dataSource
}
}
@StateObject
- WWDC 2020에서 애플은
@StateObject
를 추가로 공개했습니다. @ObservedObject
와 거의 같은 방식으로 작동하는데요.- SwiftUI가 View를 다시 랜더링 할 때, 실수록 취소되는 것을 방지해줍니다.
struct ContentView: View {
@StateObject var user = User()
}
@ObservedObject
- SwiftUI는
@ObservedObject
를 통해 view가 외부 객체를 감지하게 해줍니다. - 아래 코드에서 User class는 ObservableObject를 준수하고
@Published
변수를 갖고 있습니다. @ObservedObject
user 변수는 이러한 User class 객체를 담고 있습니다.- SwiftUI는 이러한 user 객체의
@Published
변수 값이 변경될 때 view를 refresh합니다.
class User: ObservableObject {
@Published var name = "Hohyeon Moon"
}
struct ContentView: View {
@ObservedObject var user = User()
var body: some View {
VStack {
Text("Your name is \(user.name).")
}
}
}
@EnvironmentObject
@EnvironmentObject
는 보통 앱 전반에 걸쳐 공유되는 데이터에 사용됩니다.@EnvironmentObject
는 .environmentObject()
를 통해 값을 전달할 수 있습니다.- 전달하는 object는 ObservableObject 프로토콜을 준수해야 합니다.
- 아래 코드와 같이 root view를 제공하면, 어떠한 view에서도 사용이 가능합니다.
class Settings: ObservableObject {
@Published var version = 0
}
var settings = UserSettings()
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(settings))
struct ContentView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
NavigationView {
VStack {
Button(action: {
self.settings.version += 1
}) {
Text("Increase version")
}
NavigationLink(destination: DetailView()) {
Text("Show Detail View")
}
}
}
}
}
struct DetailView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
Text("Version: \(settings.version)")
}
}
총 정리

마무리
- 이렇게 해서 SwiftUI에서는 라이프사이클과 데이터 흐름을 어떻게 처리하는지 알아봤습니다.