아요 개발 일기
[SwiftUI] Property Wrapper - @State, @Binding 본문
안녕하세요~ 소진입니다 😄
오늘은 SwiftUI의 Property Wrapper에 대해 알아보겠습니다!
양이 많을 수 있지만, 차근차근 가봅시다! 🐢
@State
SwiftUI의 View는 struct이고, 이는 언제나 소멸되거나 재생성됩니다.
하지만 struct는 값 타입이기때문에 struct내의 값을 변경 할 수 없습니다
이때, SwiftUI는 @State를 제공해 struct내의 값을 변경할 수 있게 해줍니다.
(@State를 사용해 지속적으로 변형 가능한 변수를 만듬)
즉, @State를 앞에 추가하면 SwiftUI가 자동으로 변경사항을 Observe하고
해당 @State를 사용하는 view 부분을 업데이트합니다.
자, 이제 본격적으로
공식문서 부시러 가봅시다!
" SwiftUI에서 관리하는 값을 읽고 쓸 수 있는 property wrapper type입니다."
라고 설명하고 있네요!
위에서 잠깐 설명한 것을 짧게 간추린 버전같죠? ㅎㅎ
Overview가 길지만...
다 알아야하기때문에! 읽어봅시당
- SwiftUI는 @State(상태)로 선언한 모든 property(속성)의 storage(저장소)를 관리
- 값이 변경될때, SwiftUI는 값에 의존하는 view 계층 구조 일부를 업데이트
- view 계층 구조에 저장된 value의 @State는 single source of truth를 사용
- @State는 String, Int, Bool과 같은 간단한 타입에만 사용되는 것이 좋음
- State 인스턴스는 value 자체가 아니며 읽고 쓰는 수단임
그래서 자식 view에 @State property를 전달하면 SwiftUI는 부모가 값이 변경될 때마다 자식을 update하지만,
자식은 값을 modify(수정)할 수 없음 이때 자식 view의 수정하기가 활성화되도록 하려면
저장된 값을 Binding instead을 전달해야 함
- property 이름에 dollar 표시인($) 접두사를 붙여 얻을 수 있는
projectedValue state에 접근하여 state value에대한 바인딩을 얻을 수 있음
- @State 변수는 private으로 선언하고, view 계층 구조의 최상위 view에 배치하여 다른 view와 공유되지 않음
왜냐하면 SwiftUI에서 제공하는 storage와 충돌할 수 있어서 view를 instance화하는 view 계층에서는 view state를 초기화하면 안 됨.
만약, 다른 view와 값을 공유하고 싶다면 @StateObject나 @ObservedObject를 사용
살짝 글만 읽는데 숨차네요,,
이럴때는
예시를 봅시다!
SwiftUI의 segmentedControl를 사용해볼꺼에요
struct SegementedControlView: View {
var body: some View {
VStack {
Picker("", selection: .constant(0)) {
Text("A").tag(0)
Text("B").tag(1)
Text("C").tag(2)
}.pickerStyle(SegmentedPickerStyle())
}
.padding()
}
}
selection 파라미터가 binding을 받는 곳 인데,
.constant(0)이 들어가있죠?
그 constant때문에 selection이 0(=A)에서 바뀌지 않습니다.
위처럼 아무리 눌러도 0(=A)에서 변하지 않습니다.
이때 @State property를 사용하면 됩니다!
struct SegementedControlView: View {
@State private var selectedIndex = 0
var body: some View {
VStack {
Picker("", selection: $selectedIndex) {
Text("A").tag(0)
Text("B").tag(1)
Text("C").tag(2)
}.pickerStyle(SegmentedPickerStyle())
}
.padding()
}
}
위처럼 @State property를 선언해주고
해당 @State property를 selection에 binding 해줍니다!
binding 값은 위에서 설명한 것처럼
dollar($)연산자를 이용하여 얻을 수 있습니다.
아주 잘 변경되네요!
뭔가 예시로 보니까 이해가 잘 되죠?ㅎㅎㅎㅎ
@Binding
"source of truth가 소유한 값을 읽고 쓸수 있는 property wrapper입니다"
무슨 소리야..
OverView를 봅시다!
- 데이터를 저장하는 state와 데이터를 표시하는 state간에 양방향 연결을 만듬
- 데이터를 직접 저장하는 대신 state를 다른 곳에 있는 source of truth stored(저장소)에 연결함
무슨 소리지?
글로만 보는건 어려우니!
이번에도 예시 코드를 봅시당~.~
위처럼 버튼이 true일때는 Pause
false일때는 Play로 나오도록 하겠습니다!
struct ButtonView: View {
@State private var isPlaying: Bool = false
var body: some View {
VStack {
PlayButton(isPlaying: $isPlaying)
.buttonStyle(.bordered)
} .foregroundColor(.green)
}
}
위는 ButtonView를 구성한 부분입니다
@State로 isPlaying을 선언하고, 기본 Bool 값은 false로 설정하겠습니다.
body 내부에서
$기호를 사용하여 isPlaying의 값을 받아온 후,
그 값을 이용해 View를 출력합니다.
저희가 true일때는 Pause
false일때는 Play로 나오게하기로 했죠?
struct PlayButton: View {
@Binding var isPlaying: Bool
var body: some View {
Button(isPlaying ? "Pause" : "Play") {
isPlaying.toggle()
}
}
}
그 부분을 할 수 있도록 해주는 코드입니다!
isPlaying 값을 @Binding 해주고,
삼항 연산자를 이용해 Button에 출력되는 택스트를 선택해주고
.toggle을 이용하여 버튼의 상태를 전환해줍니다.
잘 전환되네용ㅎㅎ
오늘 포스팅은 글이 너무 길어질 것 같아서
이정도로만 하고!
다음은 다른 Property Wrapper
@Published, @ObservedObject, @StateObject, @EnvironmentObjec을 공부하기 전에
ObservableObject에 대해 포스팅하도록하겠습니다!
다음 포스팅에서 만나용 🥰
'UI > SwiftUI' 카테고리의 다른 글
[SwiftUI] Property Wrapper - @Published, @ObservedObject, @StateObject, @EnvironmentObjec (0) | 2023.01.03 |
---|---|
[SwiftUI] Table View 만들기 (0) | 2023.01.02 |
[SwiftUI] Container View (0) | 2023.01.02 |
[SwiftUI] Life Cycle (0) | 2023.01.02 |
[UI] Storyborad(UIKit) vs SwiftUI (0) | 2023.01.02 |