이번에는 간단한 예시를 가지고 State, Binding에 대해서 알아보겠습니다.
버튼을 눌러 숫자를 증가 감소시키는 화면이 있습니다. 먼저 ContentView 코드를 살펴보겠습니다.
struct ContentView: View {
@State var number: Int = 0
var body: some View {
VStack {
Text(String(number))
.font(.largeTitle)
.bold()
HStack {
Button {
number -= 1
} label: {
Text("minus")
.foregroundColor(.white)
.padding()
.padding(.horizontal)
.background(.red)
.cornerRadius(10)
}
Spacer()
Button {
number += 1
} label: {
Text("plus")
.foregroundColor(.white)
.padding()
.padding(.horizontal)
.background(.blue)
.cornerRadius(10)
}
}
.padding()
}
.padding()
}
}
코드를 보면 number
는 State로 선언되어 있는 걸 볼 수 있습니다.
공식 문서를 보면 State는 값을 읽고 쓸 수 있는 Property Wrapper라고 합니다.
여기서 궁금한 점은 굳이 @State를 붙여야 하는가입니다. 그냥 number를 변경시키면 되지 않을까 생각할 수 있습니다.
@State 키워드를 제거하게 되면 사진과 같은 에러를 확인할 수 있습니다.
ContentView는 struct로 구현되어 있습니다. 즉 struct는 immutable 한 성격을 가지고 있기 때문에 자신이 가지고 있는 property를 그냥 변경 시킬 수 없습니다. 그렇기 때문에 @State를 사용해야 합니다.
이제 Binding에 대해서 알아보겠습니다. 그전에 먼저 위에 코드가 지저분한 것 같으니 Button을 만드는 코드를 먼저 분리하겠습니다.
struct UpDownButton: View {
@Binding var number: Int
var body: some View {
HStack {
Button {
number -= 1
} label: {
Text("minus")
.foregroundColor(.white)
.padding()
.padding(.horizontal)
.background(.red)
.cornerRadius(10)
}
Spacer()
Button {
number += 1
} label: {
Text("plus")
.foregroundColor(.white)
.padding()
.padding(.horizontal)
.background(.blue)
.cornerRadius(10)
}
}
.padding()
}
}
UpDownButton의 number 앞에는 @Binding이 붙어있습니다. Binding은 Source의 값을 읽고 쓸 수 있는 Property Wrapper입니다.
Binding을 사용하면 데이터를 저장하는 속성과 데이터를 변경하고 표시하는 화면 간의 양방향 연결을 만들 수 있습니다. Binding을 통해 데이터를 저장하는 대신 Property는 다른 곳에 저장된 소스에 연결합니다.
그럼 수정 된 ContentView 코드를 보겠습니다.
struct ContentView: View {
@State var number: Int = 0
var body: some View {
VStack {
Text(String(number))
.font(.largeTitle)
.bold()
UpDownButton(number: $number)
}
.padding()
}
}
코드를 보면 이제 상위 뷰는 ContentView가 되고 하위 뷰는 UpDownButton이 됩니다. 즉 하위 뷰에서 number를 수정하지만 ContentView의 number에 연결되어 있다고 이해하면 될 것 같습니다.
Binding 속성을 전달하고 싶다면 ($) 기호를 사용해야 합니다.
SwiftUI는 각각의 View를 객체화해 조합해서 사용할 수 있다는 큰 장점이 있습니다. 여기서 struct를 통해 각각의 View를 구현하게 되는데 struct 특성 상 자신의 property를 그냥 변경할 수 없습니다. 또한 같은 데이터를 공유하는 View 사이를 연결 시켜주기 위해서는 @State와 @Binding을 사용해야 합니다.