- [Property Wrapper]@State, @Biniding, @Observable, @Bindable2025년 06월 14일 23시 17분 24초에 업로드 된 글입니다.작성자: 이중엽
UIKit을 다루다 SwiftUI를 공부하면 처음보는 여러 Property Wrapper를 마주하게 된다.
그 중 오늘 공부한 Property Wrapper들을 정리하려고 한다.
우선 두 개념을 설명하기 앞서, SwiftUI에서는 기존 View가 class기반에서 struct기반으로 변경되었다.
이유는 SwiftUI 선언형 UI로 상태에 따라 뷰를 새롭게 그려주기 때문이다.
이때 class(참조 타입)는 기존 인스턴스를 유지하는 방면, struct(값 타입)은 새롭게 인스턴스를 생성하며 view를 그려주기 때문에 view가 안정적이다.
안정적인 이유는 생성된 인스턴스가 여러곳에서 참조되고 있다면 상태의 변경을 추적하기 어렵다.
class A { var x = 0 } let a = A() let b = a b.x = 3
위 예시만 보아도 b에서 내부 프로퍼티 x를 변경했지만, a에서도 내부 프로퍼티 x가 변경된다.
b가 a를 참조하고 있기 때문이다.
이는 사이드 이펙트를 발생하기 쉽고 이러한 이유로 안정성이 떨어진다고 볼 수 있다.
그렇지만 값 타입인 struct은 Copy On Write가 바탕이기 때문에 a와 b는 서로 다른 인스턴스로 서로에게 영향을 끼치지 않는다. 즉, 참조의 개념이 아니기 때문에 이러한 사이드 이펙트로 부터 안정적이다.
@State
위 내용을 이해했으면 State가 왜 생겼는지 이해할 수 있다.
앞서 말했듯 SwiftUI는 값이 변경되어 View를 새롭게 그린다(새로운 인스턴스를 생성한다)고 했다.
그렇기 때문에 어떠한 상태값을 지닌 내부 프로퍼티가 있다고 가정했을 때,
내부 프로퍼티의 값(상태)을 변경하더라도 인스턴스는 새로 생성되고 변경된 상태 값을 새롭게 생성된 인스턴스는 이를 알 길이 없다.
즉, 상태를 변경했는데 View가 새로운 인스턴스(View)가 생성되면서 변경된 상태를 모르고 초기화된다.
그러면 State의 역할은?
인스턴스(View)가 새로 생성되어도 상태값만은 따로 저장해주는 역할을 한다.
내부 로직은 잘 모르겠다 하지만, 간단한 설명에 따르면
@State Wrapper를 사용하면 Stack에 메모리가 저장되는 struct의 내부 프로퍼티임에도 Heap영역에 그 데이터가 저장된다고 한다.
따라서 인스턴스(View)가 새롭게 생성되어도 프로퍼티(상태값)는 Heap 영역에서 참조가 가능하기 때문에 값의 변경을 저장하고 있을 수 있다.
- Memberwise Initialize(struct에서 자동으로 생성되는 init)와 충돌을 방지하기 위해 State 변수는 Private으로 생성한다
- State Property는 항상 기본값을 제공해야한다. 그렇지 않을 경우 화면의 업데이트가 빈번할 경우 비용이 많이 발생한다.
- task(priority:_:)를 통해 초기화를 연기시킬 수는 있다.
- Binding 프로퍼티에게 값을 전달할 때 '$'를 붙인다.@Binding
binding 뭔가를 꽉 붙잡고있는 이미지가 그려지는가? 그러면 절반은 이해한게 맞다
화면에 보여지는 상위 뷰(Screen View)에는 하위 뷰(Component View)들이 존재할 수 있다.
예를 들어 List에 들어가는 하위 View가 있다.
(UIkit에서 Cell이라고 이해하면 될 듯 하다)
이때 상위 뷰에서 하위 뷰로 상태 값(property)을 전달 할 수 있다.
상위 뷰에서 상태 값이 변경되면 의존된 하위 뷰 까지 모드 업데이트하지만, 하위 뷰에서는 상위 뷰의 상태 값을 변경할 수 없다.
이 때 Binding으로 상위 뷰로 부터 받을 상태값(프로퍼티)를 정의한다면, 상위 뷰의 상태 값을 변경할 수 있다.
쉽게 참조된 데이터를 똑같이 참조한다고 이해하면 쉽다.
- State 상태 값을 받는다고 해서 꼭 Binding을 사용할 필요는 없다, 하위 뷰에서 상태 값의 변경이 필요할 때만 사용하면 된다.
- 상태값을 변경할 때는 '$'를 붙인다.@Bindable
bindable은 binding이랑 관련깊어 보이지만, state의 다른 형태라고 이해하면 된다.
기본적으로 state는 단일 값(상태)를 저장한다. 예를 들어 Bool, Int와 같은
Bindable은 class형태로 이루어진 객체 수준의 프로퍼티의 상태값 변경을 감지하게 해준다.
@Observable
앞서 Bindable이 class 객체의 프로퍼티의 상태 값 변경을 감지할 수 있도록 해준다고 했다.
하지만 역시나, 아무 class라고 다 Bindable이 가능한 것은 아니다.
class의 상태값 변경을 감지 가능한 상태로 만들어주는 Property Wrapper라고 이해하면 된다.
Bindable을 하지 않아도 상태값 변경을 감지하긴 하지만, 하위 뷰가 읽는 property만 감지가 가능하다.
다음글이 없습니다.이전글이 없습니다.댓글