Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[이준복] Data Essentials in SwiftUI ‐ @StateObject, @ObservableObject, @EnvironmentObject

junbok97 edited this page Jul 30, 2024 · 2 revisions

https://junbok97.tistory.com/366

요약

  • SwiftUI는 View와 View의 State관리가 중요
  • SwiftUI는 @State 를 통해 Single Source of Truth(SOT) 를 나타낼수 있음
  • SwiftUI는 @State 로 선언된 상태 프로퍼티의 저장소를 관리
  • @Binding 을 통해 Single Source of Truth(SOT) 에 접근 가능
  • @Binding 을 할때는 @State 로 선언된 상태 프로퍼티의 이름에 prefix로 $표시를 추가해 사용
  • SwiftUI는 State프로퍼티가 변하면 State프로퍼티 가 포함된 View 계층구조의 일부 View들을 업데이트

SwiftUI가 가장 중요하게 생각하는 것

  • Single Source of Truth(SOT) 에 의한 상태(State) 관리
  • UIKit에서는 데이터가 여기저기서 주고 받아지고, 그렇게 받아진 데이터를 여기저기서 수정. 결국에는 어떤게 진짜인지 헷갈리고 복사된 데이터 값들이 다 다르다 보니 버그에 취약해지기 때문에 개발자가 신경써야할 게 많았음. SwiftUI에선 그런 고민들을 시스템에서 다 처리해주자 !

State, Binding은 Value Type을 위한 프로퍼티 래퍼

  • 지난 글을 통해 배운 @State, @Binding 이 두가지의 프로퍼티 래퍼는 Value Type을 위한 것
  • struct, enum, Int, Bool

그렇다면 Reference Type의 프로퍼티 래퍼는 ??

  • @StateObject, @ObservedObject, @EnvironmentObject
  • @EnvironmentObject 는 후반부에서 계속
  • Single Source Of Truth
    • Value : @State
    • Reference : @StateObject
  • Reference of SOT
    • Value : @Binding
    • Reference : @ObservedObject

protocol ObservableObject

1
2
3

  • 프로퍼티 래퍼 @StateObject, @ObservedObject 를 사용하려면 class에선 protocol ObservableObject 을 채택해주어야 함
  • protocol ObservableObjectAnyObject 를 채택 중 즉 class Type만 사용가능하다
  • class에 ObservableObject 을 채택하고 class 내에서 관찰할 프로퍼티에 @Published 를 사용
4
  • @Published 프로퍼티에서 변화가 생기면 값을 방출하여 SwiftUI가 뷰를 다시 그림
    • 값을 어디로 방출?
    • protocol ObservableObjectobjectWillCahnge
class ReadingListStore: ObservableObject {
 @Published var listName: String = "Book List"
}

@ObservedObject

5
  • ObservableObject class 를 관찰하려는 View에서 @observedobject 를 붙혀 사용
  • @observedobject 는 뷰 내부에서 직접 초기화가 가능
  • 하지만 @observedobject 는 인스턴스를 소유하고 있지 않고 있기 때문에 문제가 발생
6 7

@StateObject

8
struct ReadingList: View {
 @StateObject private var store = ReadingListStore()
 
 var body: some View {
 ReadingItem(store: store)
 }
}
struct ReadingItem: View {
 @ObservedObject var store: ReadingListStore
 
 var body: some View {
 }
}

그림으로 쉽게 이해하기

9
10
11
12

Note that the lifetime of a view is separate from the lifetime of a struct that defines it.

@EnvironmentObject 는 왜 생겨났나

  • ObservableObject 가 필요한 곳이 멀리 떨어져 있다면 ?
13
  • ObservableObject 가 필요하지 않은 뷰임에도 하위 뷰로 전달하기 위해서 추가해주어야 함
14
class MyObservableObject: ObservableObject { }
struct View1: View {
 @StateObject var myObservableObject = MyObservableObject()
 
 var body: some View {
 View2(myObservableObject: myObservableObject)
 }
}
struct View2: View {
 @ObservedObject var myObservableObject: MyObservableObject
 
 var body: some View {
 View3(myObservableObject: myObservableObject)
 }
}
struct View3: View {
 @ObservedObject var myObservableObject: MyObservableObject
 
 var body: some View {
 View4(myObservableObject: myObservableObject)
 }
}
// myObservableObject 필요한 곳
struct View4: View {
 @ObservedObject var myObservableObject: MyObservableObject
 
 var body: some View {
 myObservableObject
 }
}
  • 이럴때 사용하는 것이 @EnvironmentObject
15
  • 뷰에 environmentObject 로 등록하면 계층구조에 상관없이 접근 가능
  • @EnvironmentObject 를 사용하여 ObservableObject 가 필요한 뷰에서 접근
class MyObservableObject: ObservableObject {}
struct MyContentView: View {
 var body: some View {
 View1()
 .environmentObject(MyObservableObject())
 }
}
struct View1: View {
 
 var body: some View {
 View2()
 }
}
struct View2: View {
 
 var body: some View {
 View3()
 }
}
struct View3: View {
 var body: some View {
 View4()
 }
}
struct View4: View {
 @EnvironmentObject var myObservableObject: MyObservableObject
 
 var body: some View {
 myObservableObject
 }
}

Luckily, we have a solution for this problem with EnvironmentObject. EnvironmentObject is both a view modifier and a property wrapper.

참고

https://developer.apple.com/videos/play/wwdc2020/10040/

https://developer.apple.com/documentation/Combine/ObservableObject

https://developer.apple.com/documentation/combine/published

https://developer.apple.com/documentation/swiftui/observedobject

https://developer.apple.com/documentation/swiftui/stateobject

https://developer.apple.com/documentation/Combine/ObservableObject

https://developer.apple.com/documentation/swiftui/environmentobject

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /