iOS 기본 (SwiftUI)

[iOS - SwiftUI] @EnvironmentObject 사용 방법 (뷰 간 데이터 공유 방법, .environmentObject())

jake-kim 2022. 10. 29. 23:29

목차) SwiftUI의 기본 - 목차 링크

@EnvironmentObject 란?

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

  • parent 뷰에서 정의한 observable 객체이며, subview들이 접근 가능한 프로퍼티로 property wrapper 타입
    • 즉, parent 뷰에서 subview에 특정 상태를 주입하여, subview에서 그 상태에 접근할때 사용
    • subview에서 superview로부터 주입받은 @EnvironmentObject 프로퍼티를 변경시키면 부모에서도 모두 뷰가 업데이트
    • 전역적으로 데이터를 공유하는 형태이므로, 뷰 간 데이터를 공유할때 사용
  • 내부 코드
    • dynamicMember keyPath로 해당 프로퍼티에 접근할때 dot(.)로 접근이 가능
    • ObservableObject 타입을 준수할때 사용이 가능
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper public struct EnvironmentObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {
    @dynamicMemberLookup @frozen public struct Wrapper {
        public subscript<Subject>(dynamicMember keyPath: ReferenceWritableKeyPath<ObjectType, Subject>) -> Binding<Subject> { get }
    }
    @inlinable public var wrappedValue: ObjectType { get }
    public var projectedValue: EnvironmentObject<ObjectType>.Wrapper { get }
    public init()
}

EnvironmentObject 사용하여 뷰간 데이터 공유 방법

  • 자식으로 EnvironmentObject 인스턴스를 보내야 하는데, 이 때 모델은 ObservableObject를 준수해야 하므로 따로 모델을 정의
class MyObservableObject: ObservableObject {
  @Published var isOn = false
}
  • @StateObject로 선언하여 자식에게 넘겨줄 인스턴스 준비
struct ContentView: View {
  @StateObject var myObject = MyObservableObject()
  
  var body: some View {
    VStack {
      Text(myObject.isOn ? "isOn" : "isOff")
    }
  }
}
  • myObject를 하위 뷰로 넘겨주고, 이 때 하위 뷰에서 myObject의 isOn 값을 변경하면 부모 뷰인 ContentView에도 적용이 되는지 확인할 것
    • subview인 MyView를 정의하고 이를 ContentView에 subview로 준비
    • subview로의 주입은 .environmentObject()로 주입
struct MyView: View {
  @EnvironmentObject var myObject: MyObservableObject // ObservableObject타입을 준수해야됨
  
  var body: some View {
    Button(myObject.isOn ? "child, isOn" : "child, isOff") {
      myObject.isOn.toggle()
      print(myObject.isOn)
    }
  }
}

struct ContentView: View {
  @StateObject var myObject = MyObservableObject()
  
  var body: some View {
    VStack {
      Text(myObject.isOn ? "isOn" : "isOff")
      Divider()
      MyView() // <-
        .environmentObject(myObject)
    }
  }
}

결과) 자식 뷰 MyView()에서 주입받은 myObject의 isOn 값을 변경하면 부모 뷰에도 isOn값이 변경

* 전체 코드: https://github.com/JK0369/ExEnvironmentObject-SwiftUI

* 참고

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