새소식

인기 검색어

iOS/WWDC

[WWDC - 2020] Data Essentials in SwiftUI - @StateObject, @ObservableObject, @EnvironmentObject

  • -

[WWDC - 2019] Data Flow Through SwiftUI - @State, @Binding
[WWDC - 2020] Data Essentials in SwiftUI - @StateObject, @ObservableObject, @EnvironmentObject

요약

  • 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

  • 프로퍼티 래퍼 @StateObject, @ObservedObject 를 사용하려면 class에선 protocol ObservableObject 을 채택해주어야 함
  • protocol ObservableObject 은 AnyObject 를 채택 중 즉 class Type만 사용가능하다
  • class에 ObservableObject 을 채택하고 class 내에서 관찰할 프로퍼티에 @Published 를 사용

  • @Published 프로퍼티에서 변화가 생기면 값을 방출하여 SwiftUI가 뷰를 다시 그림
    • 값을 어디로 방출?
    • protocol ObservableObject 의 objectWillCahnge로
class ReadingListStore: ObservableObject {
    @Published var listName: String = "Book List"
}

@ObservedObject

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

@StateObject

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 {
    }
}

그림으로 쉽게 이해하기

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

@EnvironmentObject 는 왜 생겨났나

  • ObservableObject 가 필요한 곳이 멀리 떨어져 있다면 ?

  • ObservableObject 가 필요하지 않은 뷰임에도 하위 뷰로 전달하기 위해서 추가해주어야 함

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

  • 뷰에 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/

[Data Essentials in SwiftUI - WWDC20 - Videos - Apple Developer

Data is a complex part of any app, but SwiftUI makes it easy to ensure a smooth, data-driven experience from prototyping to production...

developer.apple.com](https://developer.apple.com/videos/play/wwdc2020/10040/)

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

[ObservableObject | Apple Developer Documentation

A type of object with a publisher that emits before the object has changed.

developer.apple.com](https://developer.apple.com/documentation/Combine/ObservableObject)

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

[Published | Apple Developer Documentation

A type that publishes a property marked with an attribute.

developer.apple.com](https://developer.apple.com/documentation/combine/published)

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://developer.apple.com/documentation/swiftui/observedobject)

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

[StateObject | Apple Developer Documentation

A property wrapper type that instantiates an observable object.

developer.apple.com](https://developer.apple.com/documentation/swiftui/stateobject)

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

[ObservableObject | Apple Developer Documentation

A type of object with a publisher that emits before the object has changed.

developer.apple.com](https://developer.apple.com/documentation/Combine/ObservableObject)

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://developer.apple.com/documentation/swiftui/environmentobject)

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.