class의 단일 인스턴스를 전체에서 공유할 수 있도록 하는 디자인 패턴으로,
한개만 생성해서 전역에 두고 해당 Instance에만 접근하도록 하는 것.
// 클래스
final class ProductStore: ObservableObject {
static let shared = ProductStore()
private init() {}
@Published var products = [Product]()
...
}
클래스는 상속하지 않을 것으로 final 을 붙여서 성능을 올리고,
init() 은 외부에서 접근하여 초기화 경우가 없도록 private 을 붙여주었습니다.
// SwiftUI 의 View 에서 사용 코드
struct ProductListView: View {
@ObservedObject private var productStore = ProductStore.shared
var body: some View {
VStack {
...
}
}
}
위 코드처럼 static 프로퍼티를 사용하면, ProductStore를 싱글톤으로 접근 할 수 있다.
하나의 인스턴스를 전역으로 가지고 있기 때문에,
메모리를 낭비하지 않고 공통된 객체로 공유를 편하게 할 수 있다는 장점이 있다.
하지만, 전역에서 아무렇게나 사용될 위험이 있고 ( 의존성 ↑ ),
위 코드에서 init()에 private을 붙여주었기에 생성이 제한되어 테스트에 어려움을 겪기도 한다.
또한, 멀티 쓰레드의 환경에서 싱글톤 객체가 2개가 생기는 위험이 있을 수 있다.
SwiftUI 에서 많은 뷰와 데이터를 공유할 때, 사용하게 되는 Attribute. ( ObservableObject 를 위한 속성 )
주입해 준 뷰의 하위 뷰라면, 어디든 사용가능하다.
보통 User 를 관리하는 객체를 사용한다.
( 최상위 뷰에서 주입을 해준다면 로그인 여부, 이름 등 앱의 전역에서 확인 할 수 있으니..! )
Singleton 오브젝트와 비슷하게 생각하면 될 것 같다.
// 클래스
final class ProductStore: ObservableObject {
@Published var products = [Product]()
...
}
따로 static 값을 만들어줄 필요가 없음.
// 상위 View 에서 environmentObject 인스턴스 주입
@main
struct ProductTestApp: App {
var body: some Scene {
WindowGroup {
ProductListView()
.environmentObject(ProductStore())
}
}
}
// SwiftUI 의 View 에서 사용 코드
struct ProductListView: View {
@EnvironmentObject private var productStore: ProductStore
var body: some View {
VStack {
...
}
}
}
@EnvironmentObject 로 받아서 사용. 타입만 선언.