Dependency 를 EnvironmentObject 에 넣어서 전달하는 방식으로 DI을 사용할 경우,
최상단에서 제공하는 인스턴스가 어디까지 전달되는지 확인하는 실험
class ViewModel: ObservableObject {
@Published var time = "Wait..."
init() {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
self?.time = Date().description
}
}
}
이런 ViewModel을 만들고 View에 넣어주자
struct ContentView: View {
@EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
Image(systemName: "1.square.fill")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(vm.time)
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color(UIColor.label), lineWidth: 4)
)
}
}
Preview 는 이렇게 되겠지
ContentView()
.environmentObject(ViewModel())
struct ContentView: View {
@EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
Image(systemName: "1.square.fill")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(vm.time)
Child()
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color(UIColor.label), lineWidth: 4)
)
}
}
struct Child: View {
@EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
Image(systemName: "2.square.fill")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(vm.time)
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color(UIColor.label), lineWidth: 4)
)
}
}
잘 되네!
struct Child: View {
@EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
Image(systemName: "2.square.fill")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(vm.time)
GrandChild()
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color(UIColor.label), lineWidth: 4)
)
}
}
struct GrandChild: View {
@EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
Image(systemName: "3.square.fill")
.imageScale(.large)
.foregroundColor(.accentColor)
Text(vm.time)
}
.padding()
.overlay(
RoundedRectangle(cornerRadius: 16)
.stroke(Color(UIColor.label), lineWidth: 4)
)
}
}
잘 되네!
struct DependencyInjected<Content>: View where Content: View {
let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
Group {
content()
}
.environmentObject(ViewModel())
}
}
이렇게 Environment 를 제공하는 컴포넌트를 만들면, 이렇게 사용한다
DependencyInjected {
ContentView()
}
응용1. 최상단 뷰에서 한 번만 넣어주면 모든 페이지에서 접근 가능한 의존성을 제공할 수 있다.
응용2. 뷰와 뷰 사이에 인스턴스 전달할 필요없이 필요한 곳에서 가져다 사용할 수 있다.
응용3. Environment는 View 에서 사용되는 IoC 같은 역할을 하는구나!
검토1. EnvironmentObject는 View 에서만 사용가능하구나!
검토2. 그렇다면 ViewModel 내에서 Service 등을 DI 하기 위해서는, 별도의 Container를 구성하거나, 생성자 주입으로 넣어줘야 겠구나!