@State
- 뷰 내부에서 상태를 나타내도록 사용하기 때문에 보통 private 으로 선언 한다.
- State가 변하면 뷰는 항상 최신 상태를 유지한다(State와 엮여있는 뷰가 다시 랜더링 된다)
struct SampleView: View {
@State private var text: String = ""
VStack {
TextField("텍스트 입력: ", text: $text)
Text(text)
}
...
}
- TextField로 사용자에게 텍스트를 입력받고, 해당 텍스트를 text변수에 할당한다.
- Text는 State인 text를 사용하므로 text변수의 값이 변경 될 때마다 랜더링 된다.
@Binding
- 하위 뷰에서 상위 뷰의 @State 에 접근 하기 위해 사용 한다.
- 상위 뷰의 @State 변수가 변경되면, 하위 뷰에서 @Binding으로 해당 변수를 받았다면, 하위 뷰가 같이 리 랜더링 된다.
struct SampleView: View {
@State private var isEnabled = true
var body: some View {
VStack {
Toggle(isOn: $isEnabled) {
Text("is Enabled?")
}
//하위 뷰 생성시 파라미터로 State변수를 $와 함께 넘겨준다.
IsEnabled(isEnabled: $isEnabled)
}
}
}
struct IsEnabled: View {
//상위 뷰의 State인 값을 Binding으로 받아서, 상위 뷰에서 변수값이 변경되면 하위뷰도 같이 리랜더링 된다.
@Binding var isEnabled: Bool
var body: some View {
Image(systemName: isEnabled ? "wifi" : "wifi.slash")
}
}
@ObservedObject
- 해당 오브젝트의 내부 값이 변경되면, 참조하는 뷰가 리랜더링 된다.
- 해당 프로퍼티 래퍼를 사용 하려는 클래스는 반드시 ObservableObject 프로토콜을 준수 해야 한다.
- 오브젝트 내부의 필드를 뷰가 리랜더링 되는데에 사용하려면 @Published 래퍼를 사용해야 한다.
struct SampleView: View {
@ObservedObject var asdf: Asdf = Asdf();
var body: some View {
VStack {
Text(Asdf.text)
}
}
}
@Published
class Asdf: ObservableObject {
@Published var text: String
}
@StateObject
- @ObservedObject와 기능은 동일하다.
- @ObservedObject는 해당 뷰에서 오브젝트를 가지고 있고, 오브젝트의 상태가 변경되는 경우 리랜더링 되지만, @StateObject는 별도로 오브젝트를 가지고 있다.
- 때문에 뷰가 다시 생성되는 경우 ObservedObject는 오브젝트가 새로 생성되지만(데이터는 당연히 초기화)
- StateObject는 별도로 가지고 있는 오브젝트를 다시 쓴다.(데이터가 초기화 되지 않는다.)
@EnvironmentObject
- @EnvironmentObject를 사용하면, 상위 뷰에서 별도로 ObservableObject를 넘겨주지 않더라도, 사용 가능하다.
@main
struct MemeApp: App {
@StateObject private var fetcher = Fetcher()
var body: some Scene {
WindowGroup {
MemeCreator()
.environmentObject(fetcher)
//main에서 ObservableObject인 Fetcher를 생성하고, 메인 뷰 에 .envioronmentObject로 넣어준다.
}
}
}
struct Text: View {
@EnvironmentObject var fetcher: Fetcher
var body: some View {
//main에서 넣어줬던 environmentObject를 어느 뷰에서든 사용 가능하다.
}
}