SwiftUI Property Wrappers - @State

sanghoon Ahn·2023년 1월 30일
0

SwiftUI

목록 보기
1/5

@State

SwiftUI에서 관리하는 저장프로퍼티는 State로 정의합니다.

value가 변경될 때 SwiftUI는 value 따라 view hierarchy의 일부분을 변경합니다.

State instance는 자체로 값이 아니며 reading 혹은 writing만 가능합니다.

State property를 parent view에서 child view에 전달하게되면 parent에서 값이 변하면 child를 변경합니다.

이때 child에서 해당 property를 동일한 @State로 받는다면 child에서는변경시킬 수 없습니다.

child에서 변경이 필요하다면 @Binding Property Wrapper를 사용해야합니다.

binding에서 state vlaue를 얻을때는 projectedValue($)를 사용합니다.

struct PlayButton: View {
    @State private var isPlaying: Bool = false

    var body: some View {
        Button(isPlaying ? "Pause" : "Play") {
            isPlaying.toggle()
        }
    }
}

isPlaying의 state가 binding될 수 있도록 @Binding property를 사용해봅시다.

struct PlayButton: View {
    @Binding private var isPlaying: Bool = false

    var body: some View {
        Button(isPlaying ? "Pause" : "Play") {
            isPlaying.toggle()
        }
    }
}

이렇게되면 parent에서 값을 전달받아도 내부에서 변경 가능합니다.

struct PlayerView: View {
    var episode: Episode
    @State private var isPlaying: Bool = false

    var body: some View {
        VStack {
            Text(episode.title)
                .foregroundStyle(isPlaying ? .primary : .secondary)
            PlayButton(isPlaying: $isPlaying) // Pass a binding.
        }
    }
}

주의해야할 점이 한가지 있습니다. SwiftUI가 제공하는 storage management가 충돌날 수 있으니 특정 view hierarchy에서 @State property를 initialize하면 안됩니다.

위 상황을 피하기 위해서는 @State property는 항상 private로 정의해야하며 또한 접근이 필요한 view heirarchy의 최상단에 위치시켜야 합니다.

그리고 접근이 필요한 뷰들과 상태를 공유할때는 read-only를 통해서만 직접 접근할 수 있도록 하고, read-write가 필요한경우에는 binding을 통해 가능하도록 해야합니다.

@State 의 값 변경은 모든 thread에서 safe합니다.

struct StateExample: View {
	@State private var value: Int = .zero

	var body: some View {
		VStack {
			Text("The Value is \(value)"
			Button("Increment") {
				value += 1	
			}
		}
	}
}

View Object 안에서 사용되고 property가 변경될 때 view가 응답을 받을 수 있습니다.

property는 view에 종속되며 이는 외부에서 주입이 불가능하고 view가 초기화 될 때 함께 초기화됩니다.

SwiftUI는 내부적으로 property의 값을 저장하며, view를 리렌더링 해도 값을 유지합니다.

SwiftUI에서는 새로고침 할 때 view를 버리고 새로 만들기 때문에 view에 의해 state가 관리되는것은 적합합니다.

여기서 궁금한 부분, 그렇다면 매번 뷰를 다시 만들게된다면 리소스가 많이 사용되지 않을까? 🤔 https://developer.apple.com/videos/play/wwdc2020/10040/,
https://developer.apple.com/videos/play/wwdc2021/10019/
https://developer.apple.com/videos/play/wwdc2021/10022/,

일부 상황을 제외하고 외부에서 property를 변경하지 못하도록 private를 명시해주는것도 중요합니다.

@State를 사용해야하는 경우는

  • view가 warpping 하고싶은 instance를 생성하거나 소유할때
  • property의 변경에 응답해야 할 때
  • value type(struct, enum)을 wrapping할 때

@State를 reference type에도 사용할 수 있지만 각각의 instance를 소유한 chaining property들은 update를 감지하지 않습니다. 심지어 property를 @Published로 변경해도 마찬가지 입니다.

이들을 다룰 때는 @ObservedObject, @StateObject, @EnvrionmentObject 등이 유리합니다.

추가로 알아볼 내용

@State의 declaration은 아래와같다.

@frozen @propertyWrapper struct State<Value>

@frozen은 무엇일까..? 🤔

profile
hello, iOS

0개의 댓글