Property Wrapper는 감싸고 있는 속성에 변화가 생기면 해당 값을 읽거나, 아님 읽고 어떤 동작을 하거나, 아니면 새로 쓸 수 있는 녀석들이다.
@State는 뷰 내부에서 상태를 관리하기 위해 사용된다.
- 상태가 변경되면 뷰가 다시 렌더링 된다.
- State 변수값이 변경되면 뷰를 다시 렌더링한다. 그렇기 때문에 항상 UI에서 보여주는 state는 최신 값이다.
- @State 속성으로 어떤 프로퍼티의 초기값을 지정했다면, 다른 값으로 재할당 할 수 없다. @Binding 변수를 통해서만 가능하다.
ㄴ 개인적으로 이 말이 잘 이해가 안가서 하단에서 좀 자세히 다뤄볼게요.
ㄴ 이건, 약간 설명이 애매모호해요.
ㄴ 결론적으로 변경이 가능합니다. 근데, 다른 @State로 값을 재할당할 수 없다는 것 같습니다.
- @State 프로퍼티는 뷰가 생성될 때 초기화되고, 이후에는 값만 변경할 수 있다.
ㄴ 중간에 State를 만들어낼 수 없다는 소리이다.
import SwiftUI
struct ContentView: View {
// @State를 사용하여 상태 변수를 선언합니다.
@State private var counter = 0
var body: some View {
VStack {
// 상태 변수를 사용하여 텍스트를 표시합니다.
Text("Counter: \(counter)")
// 버튼을 눌렀을 때 상태 변수를 변경합니다.
Button(action: {
counter += 1
}) {
Text("Increment")
}
}
}
}
근데 위와 같은 설명이라면 다음과 같은 코드는 안될거에요.
import SwiftUI
struct ContentView: View {
// @State를 사용하여 상태 변수를 선언합니다.
@State private var counter = 0
var body: some View {
VStack {
// 상태 변수를 사용하여 텍스트를 표시합니다.
Text("Counter: \(counter)")
HStack{
// 버튼을 눌렀을 때 상태 변수를 변경합니다.
Button(action: {
counter += 1
}) {
Text("Increment")
}
Button(action :{
_counter = State(InitialValue : 10)
counter = _counter
}){
Text("이건 안되죠")
}
}
}
}
}
값을 변경할 수는 있지만, 아예 State를 다른 State로 만들어서 바꾸려고 하는 건 안됩니다.
@Binding은 부모 뷰로부터 전달된 상태를 자식 뷰에서 읽고 쓸 수 있도록 한다.
상태를 직접 소유하지 않지만, 부모 뷰와 상태를 공유한다.
import SwiftUI
struct ParentView: View {
// 부모 뷰에서 상태 변수를 선언합니다.
@State private var counter = 0
var body: some View {
VStack {
Text("Counter: \(counter)")
// 자식 뷰에 상태 변수를 바인딩으로 전달합니다.
ChildView(counter: $counter)
}
}
}
struct ChildView: View {
// @Binding을 사용하여 바인딩 변수를 선언합니다.
@Binding var counter: Int
var body: some View {
Button(action: {
counter += 1
}) {
Text("Increment from Child")
}
}
}
이건 쓸일이 많고, 리액트의 Props 과 같은 느낌이에요!
리액트도 렌더링의 조건이 몇가지 있잖아요!
1. 부모가 준 prop이 변경될 때
2. 상태가 변경될 때
3. 강제로 리렌더링 시킬때
4. 구독하고 있는 전역 상태가 변경되었을 때
(이게 다 맞나?) 결국에 UI를 프레임워크들은 상태를 중요하게 볼 수 밖에 없는 것 같아요.
@ObservedObject는 ObservableObject 프로토콜을 준수하는 객체를 관찰한다.
- @Published로 선언된 객체의 속성이 변경되면 뷰가 다시 !렌더링!된다.
- 주로 뷰 외부에서 생성된 데이터 모델을 뷰가 관찰하도록 할 때 사용된다.
@Published : ObservableObject 프로토콜을 준수하는 클래스 내에서 사용할 수 있는 프로퍼티 래퍼이다.
import SwiftUI
import Combine
// ObservableObject 프로토콜을 준수하는 클래스입니다.
class CounterModel: ObservableObject {
// @Published를 사용하여 상태 변수를 선언합니다.
@Published var counter = 0
}
struct ContentView: View {
// @ObservedObject를 사용하여 관찰 객체를 선언합니다.
@ObservedObject var counterModel = CounterModel()
var body: some View {
VStack {
// 관찰 객체의 상태 변수를 사용하여 텍스트를 표시합니다.
Text("Counter: \(counterModel.counter)")
// 버튼을 눌렀을 때 관찰 객체의 상태 변수를 변경합니다.
Button(action: {
counterModel.counter += 1
}) {
Text("Increment")
}
}
}
}
상태와 관련된 프로퍼티 래퍼를 몇가지 더 살펴보자!
@StateObject
- @State와 유사하지만 ObservableObject 프로토콜을 준수하는 객체를 관리한다.
- 주로 뷰의 생명주기동안 객체를 소유하고 관리하는데 사용되고
- @ObservedObject와 다르게, @StateObject는 뷰가 처음 생성될 때 한번만 초기화되며, 뷰가 다시 렌더링 될 때 초기화되지 않는다.
- 이것은 마치 리액트의 ref와 비슷하다.
import SwiftUI
import Combine
class UserData: ObservableObject {
@Published var name: String = "John Doe"
}
struct ContentView: View {
// @StateObject로 데이터 모델을 관리
@StateObject private var userData = UserData()
var body: some View {
VStack {
Text("User name: \(userData.name)")
Button(action: {
userData.name = "Jane Doe"
}) {
Text("Change Name")
}
}
}
}
@EnvironmentObject
- 어플리케이션의 여러 뷰 계층 구조에서 공유할 수 있는 객체( ObservableObject 프로토콜을 준수하는 )를 전달하는데에 사용된다.
- 주로 앱 전역 상태나 설정을 관리할 때 유용하다.
1. 먼저, ObservableObject 프로토콜을 준수하는 전역 객체를 정의한다.
import SwiftUI
import Combine
class Settings: ObservableObject {
@Published var isDarkMode: Bool = false
}
다음으로, 이 객체를 환경에 추가하고 여러 뷰에서 사용할 수 있도록 한다.
import SwiftUI
struct ParentView: View {
// @EnvironmentObject로 전역 객체를 선언
@EnvironmentObject var settings: Settings
var body: some View {
VStack {
Text("Dark Mode: \(settings.isDarkMode ? "On" : "Off")")
ChildView()
}
}
}
struct ChildView: View {
// @EnvironmentObject로 전역 객체를 선언
@EnvironmentObject var settings: Settings
var body: some View {
Button(action: {
settings.isDarkMode.toggle()
}) {
Text("Toggle Dark Mode")
}
}
}
// 여기는 앱의 루트뷰 파일이라고 하자.
@main
struct MyApp: App {
// 환경 객체를 앱의 루트 뷰에 추가
//var settings = Settings()
// 근데 이렇게 하기 보다는
var body: some Scene {
WindowGroup {
ParentView()
.environmentObject(Settings())
// 그냥 여기서 바로 인스턴스 생성하면서 넘기자
}
}
}
'Ios > Swift UI' 카테고리의 다른 글
CloseRange (0) | 2024.07.26 |
---|---|
부모뷰에서 자식뷰로 상태를 바인딩해서 전달할 때 : $ (0) | 2024.07.26 |
@Environment (0) | 2024.07.26 |
Swift UI 메서드 정리 ( 계속 추가 ) (2) | 2024.07.24 |
이것저것 Swift 메모용(찾아갈만한게 있을 수도 있고 없을 수도 있어요) (3) | 2024.07.23 |