Post

SwiftUI 프로퍼티 래퍼

SwiftUI 프로퍼티 래퍼

SwiftUI를 사용할 때 데이터를 다른 뷰에서 사용하거나 입력을 받기 위해서 프로퍼티 래퍼를 사용한다 프로퍼티 래퍼의 사전적 의미(사용)은 뷰의 상태를 관리하고, 데이터 바인딩을 제공하며, 앱 환경을 뷰계층에 전달하는 역할을 한다고 한다

 

State 프로퍼티 래퍼

@State는 뷰의 로컬 상태를 관리하는데 사용 이 데이터가 변경되면 뷰는 재랜더링 된다 State는 보통 뷰 내부에서만 사용되고 뷰 외부로 상태를 전달하거나 공유할 수 없다

  • 용도: 뷰가 다시 랜더링되어도 유지되어야 하는 로컬 상태를 관리할 때 사용한다
  • 수명: 뷰와 함께 지속되며 뷰가 사라지면 상태도 같이 사라진다
1
2
3
4
5
6
7
8
9
10
11
12
struct CounterView: View {
    @State private var count = 0  // 로컬 상태인 count를 @State로 선언

    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("Increase") {
                count += 1  // 버튼을 누를 때마다 상태가 업데이트되고, 뷰가 다시 렌더링됨
            }
        }
    }
}

 

Binding 프로퍼티 래퍼

Binding은 부모의 뷰의 상태를 자식 뷰에서 공유하고 수정할 수 있게 해준다 자식뷰에서 부모의 상태에 직접 접근 또는 수정이 가능하다

  • 용도: 상위 뷰에서 관리하는 상태를 하위 뷰에서 수정하거나 접근 할 때 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ParentView: View {
    @State private var isOn = false  // 부모 뷰의 상태

    var body: some View {
        ToggleView(isOn: $isOn)  // 자식 뷰로 상태를 바인딩하여 전달
    }
}

struct ToggleView: View {
    @Binding var isOn: Bool  // 부모 뷰에서 전달된 상태에 바인딩

    var body: some View {
        Toggle("Switch", isOn: $isOn)  // 바인딩된 상태로 Toggle 제어
    }
}

여기서 관리할 상태는 state로 선언하고 부모 뷰에서 하위뷰로 연결할 때 하위뷰로 이 값을 전당해줘야 한다 그리고 받은 상태를 하위뷰에서 Binding 해서 이용할 수 있다

 

ObservedObject 프로퍼티 래퍼

외부 객체에서 상태를 관찰하고 그 객체의 상태가 변경될 때 뷰를 다시 랜더링한다 클래스로 선언ehlsl 객체 모델에서 사용되며 그 클래스는 ObservableObject 프로토콜을 이용해서 선언해야한다 구조체는 안되고 클래스로 만들어야한다

  • 용도: 뷰 외부에 있는 객체를 감시하고 그 객체가 변하면 뷰를 재랜더링한다
  • 요구사항: 클래스로 선언할 때 ObservableObject 프로토콜을 준수해야하고 클래스 내부 변수는 @Published 프로퍼티로 선언한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CounterModel: ObservableObject {
    @Published var count = 0  // 상태를 관찰할 수 있도록 @Published로 선언
}

struct CounterView: View {
    @ObservedObject var model = CounterModel()  // 모델 객체를 관찰

    var body: some View {
        VStack {
            Text("Count: \(model.count)")
            Button("Increase") {
                model.count += 1  // 모델 객체의 상태가 변경되면 뷰가 다시 렌더링됨
            }
        }
    }
}

 

StateObject 프로퍼티 래퍼

방금 전에 쓴 ObservedObject 프로퍼티와 비슷한 역할을 한다 하지만 생성과 삭제가 다르다 ObservedObject는 뷰가 없어져도 객체는 유지되지만 StateObject는 뷰가 생성될때 생성되고 뷰가 사라지면 객체도 사라진다

@StateObject와 @ObservedObject의 차이점

  • @StateObject: 뷰에서 객체를 처음으로 생성하고 그 객체의 상태를 관리 뷰가 새로 생성될 때마다 새로운 객체가 생성되며, 해당 객체는 뷰의 수명 주기에 맞춰 관리
  • @ObservedObject: 이미 다른 곳에서 생성된 객체를 관찰할 때 사용 객체의 생성을 뷰 외부에서 관리하고, 해당 객체의 상태를 변경 사항에 따라 감시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CounterModel: ObservableObject {
    @Published var count = 0  // @Published를 통해 상태 변화를 알림
}

struct CounterView: View {
    @StateObject var model = CounterModel()  // @StateObject로 모델을 뷰에서 직접 관리

    var body: some View {
        VStack {
            Text("Count: \(model.count)")
            Button("Increase") {
                model.count += 1
            }
        }
    }
}

이렇게 뷰에서 프로퍼티 래퍼를 작성할 때 만 다르고 사용 방법을 같다

차이점 – 코드 –

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CounterModel: ObservableObject {
    @Published var count = 0
}

struct ParentView: View {
    @StateObject var model = CounterModel()  // 객체를 생성하고 상태를 관리

    var body: some View {
        ChildView(model: model)  // 자식 뷰에 상태 전달
    }
}

struct ChildView: View {
    @ObservedObject var model: CounterModel  // 부모 뷰에서 전달된 객체를 관찰

    var body: some View {
        VStack {
            Text("Count: \(model.count)")
            Button("Increase") {
                model.count += 1
            }
        }
    }
}

이렇게 사용한다면 Binding 없이도 부모에게서 변수(상태)를 전달 받을 수 있다

 

EnvironmentObject

@EnvironmentObject는 앱으니 전역 상태를 공유하고 여러 뷰에서 쉽게 접근 할 수 있다 부모자식 관계를 넘어서 광범위하게 상태 공유 가능

  • 용도 여러 뷰에서 전역적으로 상태를 공유
  • 요구사항: 객체는 EnvironmentObject 프로퍼티 래퍼를 사용해야한다

 

프로퍼티 래퍼설명주요 용도
@State뷰의 로컬 상태를 관리하며, 상태 변경 시 자동으로 뷰를 다시 렌더링뷰 내부에서 사용되는 상태 관리
@Binding상위 뷰에서 상태를 바인딩하여 하위 뷰에서 접근하고 수정할 수 있게 함상위 뷰의 상태를 하위 뷰에서 수정
@ObservedObject
@StateObject
외부에서 상태를 관리하는 객체를 관찰하며, 상태가 변경되면 뷰를 다시 렌더링외부 모델 객체의 상태를 감시하고 변경 사항 반영
@EnvironmentObject앱 전역에서 상태를 공유하며, 여러 뷰에서 동일한 객체에 접근할 수 있음전역 상태 공유 및 여러 뷰 간 상태 동기화
This post is licensed under CC BY 4.0 by the author.