나의 발자취
[SwiftUI] @State 프로퍼티, @Binding 프로퍼티 본문
@State와 @Binding은 필요충족관계가 있다고 볼 수 있다. 이 둘은 SwiftUI에서 상태 관리를 위한 서로 다른 역할을 수행하지만, 함께 사용될 때 상위 뷰와 하위 뷰 간에 효과적으로 데이터를 공유하고 UI를 업데이트하는 데 기여한다.
@State: 상태 정의, 관리
- 상태 관리: @State는 뷰의 상태를 직접 관리한다. 상태가 변경되면 해당 뷰가 다시 렌더링된다. (뷰의 생명 주기와 밀접하게 연결)
- 소유권: @State 변수를 소유하는 뷰에서만 수정할 수 있다.
@Binding: 상태 참조(연결)
- 상태 참조: @Binding은 상위 뷰의 @State 변수를 하위 뷰에 전달할 때 사용된다. 이를 통해 하위 뷰는 상위 뷰의 상태를 읽고 수정할 수 있다.
- 상호작용: 하위 뷰에서 @Binding을 사용하면, 상태 변경이 상위 뷰에도 반영된다.
요약
- @State: 상태를 정의하고 관리하며, 해당 뷰에서만 수정 가능하다.
- @Binding: 상위 뷰의 상태를 하위 뷰와 연결하여, 하위 뷰에서 상태를 수정할 수 있게 한다.
@State
이전 시간에서, 바뀐 프레임웍 값을 SwiftUI가 보관하고 있어야하는데 그건 시스템에서 해준다.
뷰에서 변화되는 값이 필요하면, 모두 @State로 만들어준다.
// ContentView.swift
// StateTest
import SwiftUI
struct ContentView: View {
@State var framework = "Hello, UIKit!"
var body: some View {
VStack {
Text(framework)
.font(.largeTitle)
Button(action: { framework = "Hello, SwiftUI!" }, label: { Text("Change framework") })
}
}
}
#Preview {
ContentView()
}
이렇게 해주면, 아래와 같이 버튼을 클릭했을 때 상태가 바뀌게 된다.
이렇게 Preview에 아무 인자값도 없이 집어넣으면 에러가 나게 된다.
@State값을 생성했으면 #Preview값에도 기본값을 넣어주어야한다는 것
아래와 같이 생성자 초기값을 입력해주어야 에러가 나지 않는다.
구조체는 프로퍼티 목록으로 생성자를 알아서 만들어준다.
@Binding
* 이중 소스 원천
각 뷰가 각각 불을 켜고 끄는 스위치의 역할을 한다고 생각해보자. 서로의 상태를 알려면 동기화를 시켜주어야하는데, 쉽지가 않다. 한번 어긋나버리면 동기화가 되지 않기 때문에
* 단일 소스 원천
따라서, SwiftUI에서는 Single 소스 원천으로 해준다. View에 단일 소스 원천을 부여하고, (=View가 state속성을 가지고 있고), 이 데이터를 받아서 각각의 하위 View에서 처리하면 된다. 따라서 State가 바뀜에 따라, isPlaying이 자동으로 바뀌게 된다.
import SwiftUI
struct StateTest: View {
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
}
struct WifiImageView: View {
@State var wifiEnabled: Bool
var body: some View {
Image(systemName: wifiEnabled ? "wifi" : "wifi.slash")
}
}
#Preview {
WifiImageView(wifiEnabled: false )
}
#Preview에서 wifiEnabled 값을 true/false로 주느냐에 따라 이미지가 달라지도록 했다.
기본 내장 인터페이스 토글을 보면, 상태를 Binding을 통해 위쪽으로 전달할 수 있도록 기본으로 설정이 되어있다.
아래와 같이 구현을 해주고, @State isWifiEnabled를 정의해준다.
@State와 바인딩하는 방법은 $를 쓰는것이다.
일단 코드부터 먼저 작성한 후 설명.
import SwiftUI
struct StateTest: View {
@State var isWifiEnabled: Bool = true
var body: some View {
VStack {
Toggle(isOn: $isWifiEnabled) {
Text("Enable Wi-Fi")
}
WifiImageView(wifiEnabled: $isWifiEnabled)
}
}
}
struct WifiImageView: View {
@Binding var wifiEnabled: Bool
var body: some View {
Image(systemName: wifiEnabled ? "wifi" : "wifi.slash").resizable().frame(width: 110, height: 100)
}
}
#Preview {
StateTest()
}
계층구조기 때문에, 각자 값을 가지고 있는것보다 상위에서 값을 가지고 있는 것이 효율적이다.
상위 뷰인 StateTest가 @State 변수를 가지고 있어, 하위 뷰인 WifiImageView는 @Binding을 통해 이를 참조한다. 이를 통해 하위 뷰는 상위 뷰의 상태 변경에 즉시 반응하여 UI를 업데이트할 수 있다.
1. StateTest 구조체
- @State: 이 프로퍼티 래퍼는 뷰의 상태를 관리한다. 여기서는 isWifiEnabled와 name 두 개의 상태 변수를 선언한다.
- isWifiEnabled: Wi-Fi의 활성화 상태(true/false)를 나타내며, 기본값은 true이다.
- name: 사용자의 이름을 입력받기 위한 문자열이다.
- VStack: 수직 스택을 사용하여 여러 뷰를 배치한다. 여기에는 토글, Wi-Fi 이미지 뷰, 텍스트 필드가 포함된다.
- Toggle: isOn 프로퍼티에 $isWifiEnabled를 연결하여 Wi-Fi 설정을 변경할 수 있도록 한다. $ 기호는 @State변수를 바인딩으로 변환하여, 이 값이 변경될 때 UI가 자동으로 업데이트되도록 한다.
2. WifiImageView 구조체
- 이 구조체는 Wi-Fi 상태에 따라 이미지를 표시하는 역할을 한다.
- @Binding: 이 프로퍼티 래퍼를 사용하여 상위 뷰의 상태(isWifiEnabled)와 연결한다. 이를 통해 Wi-Fi 상태가 변경될 때 이 구조체도 자동으로 업데이트되어 적절한 이미지를 표시한다.
- Image: Wi-Fi 상태에 따라 다른 시스템 이미지를 표시한다. wifi 아이콘은 Wi-Fi가 활성화된 상태를, wifi.slash 아이콘은 비활성화된 상태를 나타낸다. 이미지는 리사이즈하여 지정된 크기로 표시된다.
'앱 개발 > iOS' 카테고리의 다른 글
[Swift] 접근제어자 open, public, internal, fileprivate, private (1) | 2024.10.29 |
---|---|
[SwiftUI] View Lifecycle onAppear(), onDisappear(), Picker와 Views 실습 (0) | 2024.10.29 |
[iOS] SwiftUI vs UIKit, SwiftUI 특징 (2) | 2024.10.29 |
[iOS] 스토리보드 MapKit 적용해보기 (2) | 2024.10.29 |
[iOS] BookSearch 앱 좌우 넘기기 화살표 func 하나로 일치, CoreLocation 라이브러리 (0) | 2024.10.28 |