SwiftUI는 선언형 UI 프레임워크로, 뷰의 상태 변화에 따라 UI가 자동으로 업데이트되는 강력한 기능을 제공한다. 이러한 자동 업데이트의 핵심에는 PropertyWrapper가 있다. PropertyWrapper는 데이터를 캡슐화하고 특정 로직을 적용하여 뷰와 데이터 간의 효율적인 통신을 가능하게 한다.
이 글에서는 SwiftUI 개발에 필수적인 다양한 PropertyWrapper의 개념과 용도, 그리고 iOS 17에서 새로 도입된 @Bindable까지 훑어가는 방식으로 정말 간단하게 다뤄보기로 했다.
PropertyWrapper
정의
- Swift 5.1 버전부터 도입된 문법
- 정의된 property가 있을 때 해당 property를 감싸서 특별한 타입으로 만들어준다
- 프로퍼티를 저장하는 코드와 프로퍼티를 선언하는 코드를 관리하는 그 경계를 나눠주는 기능을 추가해주는 역할
- 사용자가 별도의 코딩 없이 어노테이션만 선언해도 뷰에서 수정이나 읽기가 가능하도록 캡슐화를 대신해주는 역할
사용이유
- 프로퍼티의 접근을 특정 로직을 통해 제어할 수 있게 함. —> 중복 코드를 인스턴스로 빼내기 때문에 중복을 줄일 수 있음.
- 특정 행동을 정의하는 타입을 만드는 것. 특히, 같은 get-set을 활용하는 반복되는 로직을 재사용 해야할 때 PropertyWrapper로 정의하고 해당 로직 자리에 사용하면 동일한 로직을 수행하기 때문에 중복코드를 제거할 수 있음.
만드는 방식: @propertyWrapper 속성을 사용하여 구조체 만듬
- 연산 프로퍼티 (get, set), 저장 프로퍼티 (didSet) 등을 property wrapper로 만들어 쓸 수 있음
- 프로퍼티를 가지는 타입 앞에 붙여서 사용 (e.g. Class, Struct, Enum)
ProjectedValue
- 인스턴스 프로퍼티로 상태값에 대한 바인딩 (특정 상태의 변화를 다룰때 사용)
- projectedValue를 사용할때는 $를 붙여 사용 → @State 같은 래퍼 사용 시 $을 붙여주는 근본적 이유!
- wrappedValue는 wrapping된 내부 변수값에 접근, projectedValue는 propertyWrapper 내부에서 정의한 값을 반환 —> 즉, 해당 프로퍼티의 추가기능에 접근할 수 있음.
References
Documentation
docs.swift.org
https://ios-development.tistory.com/895
[iOS - swift] @propertyWrapper의 projectedValue 개념 ($ 접두사, 달러 접두사)
PropertyWrapper 이미 정의된 property가 있을 때, 이 property를 감싸서(wrapping) computed-property로 만든 새로운 wrapper 프로퍼티를 의미 propertyWrapper 프로퍼티 안에는 wrappedValue라는 property가 존재하며, 이 proper
ios-development.tistory.com
@State
SwiftUI에서 값을 읽고 쓸 수 있는 propertyWrapper (값 유형의 속성에 대한 저장)
- 즉, 변화가 생기면 해당 변수의 값을 읽거나 새로 쓸 수 있음을 의미함.
- 값의 변형을 감지하고 해당 값에 의존하는 뷰가 자동으로 다시 렌더링 됨.
- 상태를 변경할 때마다 body 속성이 재설정 되기 때문. —> 항상 최신값 유지
언제 사용해야할까 ?
- UI의 상태값과 같은 한정된 용도로만 사용하기를 권고 → 뷰 안에서만 사용하는 메모리 공간이기 때문. 뷰 밖의 클래스에서 사용하려면 ObservableObject를 사용해야 함.
왜 private 접근제어자를 @State와 함께 사용할까?
- @State 프로퍼티는 항상 private으로 선언하고 가장 상위 뷰에서 관리해야 한다.
- 해당 뷰가 Data를 소유하고 관리한다는 개념을 명시적으로 나타내기 위해서 함께 사용해야 한다.
- 선언한 뷰 외에선 값을 변경할 수 없기 때문에 @State 변수를 활용하려면 가장 상위뷰에 private 접근 제어자를 붙여서 초기화 단계에 설정하는 걸 방지한다. (뷰 내부 밖에선 사용 불가능하기 때문!)
- 뷰를 초기화할때, @State 프로퍼티 값도 같이 초기화하게되면 SwiftUI에서 @State 프로퍼티를 관리하는 공간인 Storage에서 conflict가 나기 때문
References
https://developer.apple.com/documentation/swiftui/state
State | Apple Developer Documentation
A property wrapper type that can read and write a value managed by SwiftUI.
developer.apple.com
https://velog.io/@suhwj/SWIFTUI-STATE
SWIFTUI @STATE
UIKit 을 사용했을 때는 어떠한 변수에 변화가 생기면 해당 변화를 직접 관찰하고 반영 해 주어야 했는데 SwiftUI 에서는 property wrapper 를 활용해 이러한 작업을 자동화 할 수 있도록 했다.변화가 생
velog.io
@Binding
두 개의 뷰 간에 데이터를 공유하고 업데이트 (데이터의 양방향 바인딩을 구현하기 위해 사용되는 wrapper!)
언제 사용할까?
- 바인딩 속성은 값의 참조를 저장하기 때문에 부모 뷰와 자식 뷰가 같은 데이터를 참조하게 된다.
- 자식뷰 → 업데이트 → 부모뷰 또한 업데이트 되어 동일한 값 유지. 반대의 경우도 같다.
- 한 바인딩 속성을 여러 뷰에서 사용하면, 해당 데이터에 대한 변경 사항은 모든 연결된 뷰에 동시에 반영.
Reference
https://developer.apple.com/documentation/swiftui/binding
Binding | Apple Developer Documentation
A property wrapper type that can read and write a value owned by a source of truth.
developer.apple.com
@StateObject
관찰중인 객체의 변경에 반응해서 화면을 업데이트할 수 있게 해주는 SwiftUI의 프로퍼티 래퍼
- @StateObject를 통해서 관찰되고 있는 객체는 그들을 가지고 있는 화면 구조가 다시 렌더링 되어도 초기화 되지 않는다.
- 객체가 변하기 전에 퍼블리싱하는 퍼블리셔를 갖는다! 이 역할은 클래스를 인스턴스화하고 observableObject 내에 있는 @Published 속성의 변수가 변화할 때 willSet 기능을 통해 뷰를 업데이트 해줌.
- @State vs @StateObject
- 앱의 특정 화면에서 인스턴스화 하고 유지하려하는 observableObject 클래스의 데이터가 존재할 때 사용한다. → Struct 타입만을 사용하려고 하면 @State를 사용할 것.
References
https://developer.apple.com/documentation/swiftui/stateobject?changes=_9
StateObject | Apple Developer Documentation
A property wrapper type that instantiates an observable object.
developer.apple.com
https://pilgwon.github.io/post/state-object-vs-observed-object
[수위프트UI/번역] @StateObject와 @ObservedObject, 무엇이 다를까요?
@StateObject vs. @ObservedObject: The differences explained
pilgwon.github.io
@ObservedObject
- 컴바인 속성
- 관찰가능한 객체를 생성함
- ObservableObject를 구독하고 해당 객체의 값이 업데이트 될 때마다 뷰를 갱신하는 PropertyWrapper.
- 즉, 모델이 뷰의 라이프 사이클에 의존적이다.
References
https://developer.apple.com/documentation/swiftui/observedobject
ObservedObject | Apple Developer Documentation
A property wrapper type that subscribes to an observable object and invalidates a view whenever the observable object changes.
developer.apple.com
https://green1229.tistory.com/228
Combine - ObservableObject / @Published / @ObservedObject
안녕하세요. 그린입니다🟢 이번 포스팅에서는 ObservableObject라는 프로토콜에 대해 학습해보겠습니다🙋🏻 추가로 이어져서 @Published와 @ObservedObject도 보시죠! 요즘 개인적으로 많이 바빠져서 블
green1229.tistory.com
StateObeject vs. ObservedObject
StateObeject와 ObservedObject는 관찰중인 객체의 상태 변경에 반응해서 화면을 업데이트할 수 있게 해주는 propertyWrapper이나, 뚜렷한 차이가 존재함.
공통점
- ObservableObject를 구독하여 이 객체의 값 변화를 감지하면 뷰에 반영해준다.
- ObservableObject란❓ 클래스 인스턴스를 관찰하다가 값이 변경되면 뷰를 업데이트 해준다. → Class 형태로만 사용이 가능하다.
차이점
- @ObservedObject 값 변화를 감지하고 뷰가 렌더링 될 때 뷰를 재생성 (값을 초기화 시킨다) → 따라서, 해당 프로퍼티는 subview에 프로퍼티를 주입해야할때 사용하는 걸 권장.
- @StateObject 화면이 다시 그려져도 항상 같은 결과를 얻을 수 있음 → 뷰가 재생성 되지 않기 때문에 값을 초기화 시키지 않는다.
References
https://www.avanderlee.com/swiftui/stateobject-observedobject-differences/
@StateObject vs. @ObservedObject: The differences explained
@StateObject and @ObservedObject have similar characteristics but differ in an important way which can lead to unexpected bugs.
www.avanderlee.com
@Published
- 컴바인 속성
- ObservableObject에서 속성을 선언할때 사용하는 PropertyWrapper.
- $ 표시를 통해 값에 접근할 수 있음.
- Observable 프로토콜을 준수해야한다.
- @Published로 선언된 속성은 해당 속성의 값이 업데이트 될때마다 뷰를 자동으로 업데이트 한다.
- ObservableObject (클래스) 와 주로 함께 사용하며, 선언 속성이 변경 될 때마다 퍼블리셔가 자동으로 호출되어 뷰를 업데이트 할 수 있다.
- 대신, 해당 객체를 사용하는 모든 뷰는 변경사항 반영을 하기 위해 뷰를 다시 그림. → @Publisehd를 쓰지 않는 한 변경사항이 있을 때 뷰를 강제로 다시 그리지 않음.
References
https://clamp-coding.tistory.com/513
SwiftUI - @ObservableObject, @ObservedObject, @Published, ObjectWillChange
@ObservableObject @ObservedObject는 ObservableObject 프로토콜을 준수하는 객체를 관찰하는 뷰 내에서 사용되는 프로퍼티 래퍼입니다. ObservableObject는 Class형태만 가능합니다. Struct형태는 불가능합니다. class
clamp-coding.tistory.com
https://green1229.tistory.com/228
Combine - ObservableObject / @Published / @ObservedObject
안녕하세요. 그린입니다🟢 이번 포스팅에서는 ObservableObject라는 프로토콜에 대해 학습해보겠습니다🙋🏻 추가로 이어져서 @Published와 @ObservedObject도 보시죠! 요즘 개인적으로 많이 바빠져서 블
green1229.tistory.com
https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-published-property-wrapper
https://developer.apple.com/documentation/combine/published
Published | Apple Developer Documentation
A type that publishes a property marked with an attribute.
developer.apple.com
@environmentObject
- 앱의 전역 상태를 나타내는데 사용함
- 뷰 간 데이터를 공유할 때 사용한다.
- parent 또는 ancestor 뷰에서 observable 객체로 정의하며, subview의 접근이 가능한 propertyWrapper이다.
- 하나의 변수가 여러 하위 계층을 걸칠 때, state-binding 구조 보다는 environmentObject를 활용하는게 좋다.
References
https://developer.apple.com/documentation/swiftui/environmentobject
EnvironmentObject | Apple Developer Documentation
A property wrapper type for an observable object that a parent or ancestor view supplies.
developer.apple.com
https://ios-development.tistory.com/1161
[iOS - SwiftUI] @EnvironmentObject 사용 방법 (뷰 간 데이터 공유 방법, .environmentObject())
목차) SwiftUI의 기본 - 목차 링크 @EnvironmentObject 란? parent 뷰에서 정의한 observable 객체이며, subview들이 접근 가능한 프로퍼티로 property wrapper 타입 즉, parent 뷰에서 subview에 특정 상태를 주입하여, sub
ios-development.tistory.com
@Bindable
- iOS 17+
- Observable을 준수하는 오브젝트에 대해 @Binding이 필요한 경우에만 @Bindable을 사용하면 된다. (state, binding...등등 다 안녕~ 할 수 있다.)
https://www.hohyeonmoon.com/blog/swiftui-data-flow
- ObservableObject →@Observable
https://www.donnywals.com/whats-the-difference-between-binding-and-bindable/
What’s the difference between @Binding and @Bindable – Donny Wals
With iOS 17, macOS Sonoma and the other OSses from this year’s generation, Apple has made a couple of changes to how we work with data in SwiftUI. Mainly, Apple has introduced a Combine-free version…
www.donnywals.com
- Apple has introduced a Combine-free version of @ObservableObject and @StateObject which takes the shape of the @Observable macro which is part of a new package called Observation.
- On iOS 17 we have access to the @Observable macro which doesn't enable us to create bindings in the same way that the ObservableObject does. Instead, if our @Observable object is a class, we can ask our views to make that object bindable.
→ iOS 17 부터 @Observable 이라는 게 생겼고, 이 객체는 클래스. 클래스에서 binding하고 싶을 때 가능케 해주는 게 bindable이다.
→ 언제 사용하는데? 뷰가 Observable 객체를 가지고 있지 않을 때 @State를 사용하는 건 적절치 못함. Bindable은 이런 경우에 객체의 프로퍼티에 바인딩을 만들 수 있도록 해주는 역할을 해준다.
References
https://eunjin3786.tistory.com/582
[SwiftUI] @Observable 매크로 (2)
[SwiftUI] @Observable 매크로 (1) 에서 이어집니다. [ 요약 ] # 1. 예전에 뷰에서 썼던 프로퍼티 래퍼 @State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject, @Enviroment iOS 17+ 부터는 4개만 쓰면 됨 @State, @Bindin
eunjin3786.tistory.com
https://developer.apple.com/documentation/swiftui/bindable
Bindable | Apple Developer Documentation
A property wrapper type that supports creating bindings to the mutable properties of observable objects.
developer.apple.com
@Binding vs @Bindable
차이점
- @Binding은 뷰의 일부 상태가 다른 뷰에 의해 소유되고 있으며, 해당 데이터에 대한 읽기 및 쓰기 접근권한을 모두 가지고 있음을 나타낼 때 사용한다.
- @Bindable은 Observable 클래스를 소유한 프로퍼티에 대한 바인딩을 생성할 수 있게 해줍니다. Observable을 준수하는 클래스에만 제한되며, Observable 객체를 만드는 가장 쉬운 방법은 @Observable 매크로를 사용하는 것.
공통점
- 강력한 데이터 공유 기능을 가능하게 하기 위해 존재한다는 공통점이 있음.
References
https://www.donnywals.com/whats-the-difference-between-binding-and-bindable/
What’s the difference between @Binding and @Bindable – Donny Wals
With iOS 17, macOS Sonoma and the other OSses from this year’s generation, Apple has made a couple of changes to how we work with data in SwiftUI. Mainly, Apple has introduced a Combine-free version…
www.donnywals.com
추가학습
The Source Of Truth
- 원본 데이터의 변화에 따라 뷰를 렌더링 해주기 때문에 데이터의 일관성과 정확성을 유지해야함.
- 상태값이 여러 곳에서 복사되고 사용되면 사이드 이펙트 위험이 있음. (무엇보다 SwiftUI의 UI는 데이터 모델에 바인딩 되어 있어서 변화값에 따라 자동으로 변경 되기 때문에 해당 개념을 인지하고 있는 것이 중요함)
- SwiftUI의 UI 업데이트는 상위뷰에 source of truth인 데이터모델 (e.g. @State…)을 두고, 하위뷰에는 값의 변화를 전달해주는 방식.
- 따라서, swiftUI에서 가장 기본이 되는 전제는 ‘뷰는 a single of source를 반영하고 있다’와 같다.
- SwiftUI에서 State와 Binding은 SSOT를 유지할 수 있도록 하는 propertyWrapper이다.
- 왜?! → @State를 통해 하나의 single source of truth가 생성 되기 때문!
- UIKit에서 데이터 변화에 따라 뷰 업데이트를 관리하는 로직 구성이 까다로웠으나, SOT를 활용하면 데이터모델과 뷰 사이에 의존관계가 생기기 때문에 데이터 상태가 변화면 뷰를 자동으로 렌더링 할 수 있도록 정의할 수 있게 됨.
- SwiftUI에서 State와 Binding은 SSOT를 유지할 수 있도록 하는 propertyWrapper이다.
Reference
https://medium.com/@eung7/the-source-of-truth-in-swiftui-state-observableobject-1421b8f80f54
The Source Of Truth in SwiftUI, State ObservableObject
SwiftUI에서 UI와 관련된 데이터 플로우에서 가장 중요한 것은 Source Of Truth입니다.
medium.com
https://80000coding.oopy.io/0930a96d-aaa5-4831-9974-03615ae1d6b6
SwiftUI) Source of Truth란???
Source of Truth란???
80000coding.oopy.io
[SwiftUI] 헷깔리는 State, Binding, ObservedObject, EnvironmentObject 총정리
SwiftUI에서의 Single Source of Truth(SSOT, 단일 진실 공급원)란 데이터의 일관성과 정확성을 유지하기 위한 중요한 개념이다. 정보 시스템에 대한 SSOT(Single Source Of Truth) 아키텍처 또는 SPOT(Single Point Of Tr
kimhaeun.com
'Dev > SwiftUI' 카테고리의 다른 글
[SwiftUI] Navigation (0) | 2024.09.24 |
---|---|
[SwiftUI] scrollTargetLayout과 ScrollTargetBehavior (0) | 2024.08.16 |
[SwiftUI] Frame (0) | 2024.07.22 |
[SwiftUI] @State (0) | 2024.05.22 |
[SwiftUI] NavigationView, NavigationStack, navigationTitle (2) | 2024.04.15 |