Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DI 관련 트러블 슈팅 - 02 #8

Open
Brandnew-one opened this issue Apr 6, 2023 · 0 comments
Open

DI 관련 트러블 슈팅 - 02 #8

Brandnew-one opened this issue Apr 6, 2023 · 0 comments
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@Brandnew-one
Copy link
Owner

Brandnew-one commented Apr 6, 2023

2) EnviornmentObject를 통한 DI는 어디까지 전파될까?

지금부터 예시로 사용한 프로젝트만 보면 DI랑 무슨 관계가 있나 싶을 수 있지만 현재 Clean-Architecture 예제의 DI를 EnvrionmentObject를 통해서 하고 있기 때문에 동일한 내용이다!

import Foundation

final class AppState: ObservableObject {
  @Published var count: Int = 0
}
import SwiftUI

@main
struct DI_TestApp: App {
  var body: some Scene {
    let appDI = AppState()
    WindowGroup {
      RootView()
        .environmentObject(appDI)
    }
  }
}

위와 같은 ObservableObject를 EnvironmentObject로 사용하면 AppState는 어디까지 전파될까?

RootView ├── TestView ── TestView2
         ├── ContentView

RootView - TestView - TestView2 는 navigation push로 스택이 쌓이는 형태이고

RootView - ContentView 는 UIKit 방식의 RootViewController를 바꿔주고 있다

import SwiftUI

struct TestView: View {
  @EnvironmentObject
  var appState: AppState

  var body: some View {
    VStack {
      NavigationLink(
        destination: { TestView2() },
        label: {
          Text("Push")
        }
      )

      Button(
        action: {
          appState.count += 1
        },
        label: {
          Text("up")
        }
      )
    }
  }
}

struct TestView2: View {
  @EnvironmentObject
  var appState: AppState

  var body: some View {
    Text("\(appState.count)")
  }
}

TestView에서 EnvironmentObject의 count 프로퍼티값을 증가시키고 TestView2로 화면전환를 한 경우, 정상적으로 증가된 Count값을 확인할 수 있다. (EnviornmentObject에 접근가능)

private func rootViewChange() {
    let window = UIApplication
      .shared
      .connectedScenes
      .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
      .first { $0.isKeyWindow }

    window?.rootViewController = UIHostingController(rootView: ContentView())
    window?.makeKeyAndVisible()
  }

하지만 해당 동작 이후, RootView에서 ContentView로 화면 전환을 시도하면 앱이 Crash가 나는것을 확인할 수 있다.

struct ContentView: View {
  @EnvironmentObject
  var appState: AppState

  var body: some View {
    VStack {
      Image(systemName: "globe")
        .imageScale(.large)
        .foregroundColor(.accentColor)

      Text("Hello, world!")

      Text("\(appState.count)")
    }
    .padding()
  }
}

이는 RootView를 바꿔주는 과정에서 enviornmetObject를 다시 주입해주지 않았기 때문에 AppState에 접근할 수 없기 때문이다.

따라서, UIKit 방식의 RootView Change를 시도하는 경우에는 UIHostingViewController에 다시 .enviornmentObject() 메서드를 통해서 사용할 ObservableObject를 다시 주입해주거나, SwiftUI 방식의 Group을 통해서 변경해주어야 한다.

프로젝트는 여기서 확인할 수 있습니다

@Brandnew-one Brandnew-one added the documentation Improvements or additions to documentation label Apr 6, 2023
@Brandnew-one Brandnew-one self-assigned this Apr 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

1 participant