일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- graphql
- RFC1738/1808
- SWIFT
- IOS
- Xcode
- Creating Operators
- vim
- NullObject
- SwiftUI
- init?
- @Environment
- @Binding
- Bug
- Operater
- Operators
- swift6
- ios14
- typeorm
- @EnvironmentObject
- operator
- dismiss
- nonisolated
- @State
- URL(string:)
- init
- nestjs
- NavigationLink
- RxCocoa
- subject
- RxSwift
- Today
- Total
Tunko Development Diary
[SwiftUI] state property 정리 (@state, @Binding) 본문
요약
- 뷰 내부에서 특정 View 의 상태를 나타내는 변수
- 뷰내부에서 밖에 사용이 불가능함 때문에 private로 선언
- 하위 뷰나 다른 뷰에서 참조하기 위해선 @Binding 해야함
- state property에 해당하는 변수 값이 변경되면 view를 다시 랜더링한다.
- 때문에 항상 최신값을 가진다.
- 뷰전체가 다시 랜더링 되는일을 막기위해 하위뷰로 데이터 변동이 반영되는 뷰만 따로 빼준다.
- 따로 뺀 뷰에 state property 를 binding 해준다.
상태프로퍼티는 상태에 대한 가장 기본적인 형태이며, 뷰 레이아웃의 현재 상태에(예를들어, 토글 버튼이 활성화되었는지 여부, 텍스트 필드에 입력된 텍스트, 또는 피커 뷰에서의 현재 선택를) 저장하기 위해서만 사용된다, 상태 프로퍼티는 String이나Int 값처럼 간단한 데이터 타입을 저장하기 위해 사용되며, @State 프로퍼티 래퍼를 사용하여 선언된다.
struct ContentView: View {
@state private var wifiEnabled = true
@state private var userName = ""
}
상태 값은 해당 뷰에 속한 것이기 때문에 Private프로퍼티로 선언되어야 한다.
상태 프로퍼티 값이 변경되었다는 것은 그 프로퍼티가 선언된 뷰 계층구조를 다시 렌더링 해야 한다는 SwiftUI의 신호다, 즉, 그 계층구조 안에 있는 모든 뷰를 빠르게 재생성하고 표시해야 한다. 결국, 그 프로퍼티에 의존하는 모든 뷰는 어떤 식으로든 최신 값이 반영 되도록 업데이트 된다.
상태 프로퍼티를 선언했다면 레이아웃에 있는 뷰와 바인딩 할 수 있다. 바인딩 되어있는 뷰에서 어떤 변경이 일어나면 해당 상태에 프로퍼티를 자동으로 업데이트할 것이다.
상태 프로퍼티와의 바인딩은 프로퍼티 이름 앞에 ‘$’를 붙이면 된다. 다음의 예제에서 TextField뷰는 사용자가 입력한 텍스트를 저장하는 데 사용하기 위해 userName이라는 상태 프로퍼티와 바인딩 된다.
struct ContentView: View {
@State private var wifiEnabled = true
@State private var userName = ""
var body : some View {
VStack {
TextField("Enter user name", text : $userName)
}
}
}
사용자가 TextField에 입력하게 되면 바인딩은 현재의 택스트를 userName 프로퍼티에 저장할 것이다. 이 상태 프로퍼티에 변화가 생길 떄마다 뷰 계층구조는 SwiftUI에 의해 다시 렌더링된다.
물론, 상태 프로퍼티에 값을 저장하는 것은 단방향 프로세스다. 앞에서 설명했듯이, 상태가 변하면 레이아웃에 있는 다른 뷰들도 변경된다. 다음의 예제에서 Text뷰는 입력된 사용자의 이름을 반영하기 위하여 업데이트되어야 한다. 이 작업은 Text뷰를 위한 콘텐트로 userName 상태 프로퍼티 값을 선언하면 된다.
var body : some View {
VStack {
TextField("Enter user name", text : $userName)
Text(userName)
}
}
사용자가 텍스트를 입력하면 Text뷰는 사용자의 입력을 반영하기 위해 자동으로 업데이트 될 것이다. 여기서 주목해야 할 점은 userName 프로퍼티가 ‘$’ 표시 없이 사용되었다는 것이다. 왜냐하면 이제는 상태 프로퍼티에 할당된 값(즉, 사용자에 의해 입력된 String값)을 참조하려고 사용하기 때문이다.
마찬가지로, 앞서 설명한 Toggle 뷰와 wifiEnabled 상태 프로퍼티 간의 바인딩은 다음과 같이 구현될 수 있다.
var body : some View {
VStack {
Toggle(isOn: $wifiEnabled) {
Text("Enable Wi-fi")
}
TextField("Enter user name", text: $userName)
Text(userName)
Image(systemName : wifiEnabled ? "wifi" : "wifi.slash")
}
}
앞의 선언부에서 Toggle뷰와 상태 프로퍼티 간의 바인딩이 구현되었다. 이 프로퍼티에 할당 된 값을 어떤 이미지를 Image뷰에 표시할지를 결정하기 위하여 사용된다.
앞의 예제에서 Image뷰는 systemName 이미지 참조체를 이용한다.
SF Symbols - Apple Developer
상태 바인딩
상태 프로퍼티는 선언된 뷰와 그 하위 뷰에 대한 현재 값이다. 하지만, 어떤 뷰가 하나 이상의 하위 뷰를 가지고 있으며 동일한 상태 프로퍼티에 대해 접근해야 하는 경우가 발생항다.
예를 들어, 앞에 예제에 있는 와이파이 이미지 뷰가 하위 뷰로 분리되는 상황을 살펴보자
struct WifiImageView: View {
var body : some View {
Image(systemName : wiwfiEnable ? "wifi", "wifi.slash")
}
}
WifiImageView 하위 뷰는 여전히 wifiEnable 상태 프로퍼티에 접근해야 한다. 하지만 분리된 하위 뷰의 요소인 Image뷰는 이제 메인 뷰의 범위 밖이다. 다시 말해 WifiImageView입장에서 보면 WifiImageView에 있는 wifiEnabled 프로퍼티는 정의되지 않은 변수인 것이다.
이 문제는 다음과 같이 @Binding 프로퍼티 래퍼를 이용하여 프로퍼티를 선언하면 해결된다.
@Binding var wifiEnabled : Bool
이제 하위 뷰가 호출 될 떄 상태 프로퍼티에 대한 바인딩을 전달하면 된다.
전체 코드 :
struct ContentView: View {
@State private var userName = ""
@State private var wifiEnabled = true
var body: some View {
VStack {
Toggle(isOn: $wifiEnabled) {
Text("Enable Wi-fi")
}.padding()
TextField("Enter user name", text: $userName).padding()
if userName.isEmpty {
Text("이름을 입력해주세요.")
} else {
Text(userName)
}
WifiImageView(wifiEnabled: $wifiEnabled)
}.border(Color.black, width: 1.5).padding()
}
}
struct WifiImageView: View {
@Binding var wifiEnabled : Bool
var body : some View {
Image(systemName : wifiEnabled ? "wifi" : "wifi.slash")
.resizable()
.frame(width: 130, height: 100, alignment: .center)
.padding()
}
}
출처 : 핵심만 골라 배우는 SwiftUI 기반의 iOS 프로그래밍 -도서-
'Development > iOS 개발' 카테고리의 다른 글
[SwiftUI] Environment 객체 정리 (0) | 2021.02.23 |
---|---|
[SwiftUI] Observable 객체 정리 (0) | 2021.02.22 |
[swiftUI] GeometryReader 부모컨테이너 기준으로 frame을 설정 (0) | 2021.02.19 |
[SwiftUI] Text 뷰 심화 정리 (2) (0) | 2021.02.18 |
[SwiftUI] Text 뷰 심화 정리 (1) (0) | 2021.02.18 |