[SwiftUI] Observable Object 초기화 트랩

9039 단어 iOSSwiftUItech

Observable Object 초기화 시 처리

SwiftUIObservableObject는 거의 모든 상황에서 함께 사용한다.논리를 ObservableObject에 통합함으로써 SwiftUI측의 코드를 간결하게 유지할 수 있다.
본론입니다. ObservableObject 초기화할 때 (init할 때) 어떤 처리를 하셨습니까?나의 경우, 때때로 Combine 등으로 수용 값을 쓰는 처리를 한다.

class DetailViewModel: ObservableObject {

  @Published var items: [String] = []

  private let someManager: SomeManager = .shared //シングルトン
  private var cancellations = Set<AnyCancellable>()

  init() {
    debugPrint("[DetailViewModel]init")
    someManager.$data
      .receive(on: DispatchQueue.main)
      .sink { [weak self] data in
        debugPrint("fetch data")
        self?.items = data.map({ $0.text })
      }.store(in: &cancellations)

  }

  func fetchData() {
    someManager.fetchData()
    //->データが取得され、someManager.dataが更新されるとします
  }

}

이 코드는 보기에 문제가 없는 것 같다.

NavigationLink와 함께 사용하는 경우


다음NavigationLink도 응용 프로그램을 구축하는 상황을 고려해야 한다.

struct ContentView: View {
  var body: some View {
      NavigationView {
        NavigationLink("Detail", destination: DetailView())
      }
  }
}

struct DetailView: View {

  @ObservedObject var viewModel = DetailViewModel()

  var body: some View {
      VStack {
        Text("DetailView")
        Text(viewModel.items.join(","))
        Button("fetch data", action: { viewModel.fetchData() })
      }
  }

}

ContentView에서 마이그레이션 대상을 선택합니다.DetailView에서 데이터를 가져오고 표시합니다.

바람직한 행위와 실제적인 행위


이러한 구성의 경우 DetailViewObservableObject로 이전하면 초기화DetailViewModel가 기대된다.
그러나 실제로ContentView가 표시되는 단계DetailViewModel에서도 초기화된다.왜 그랬을까?
아래의 보도를 참고하였다.
https://stackoverflow.com/questions/57594159/swiftui-navigationlink-loads-destination-view-immediately-without-clicking
이 글에 따르면 SwiftUI의 행동으로 설정된NavigationLinkdestinationView가 곧 초기화되었다.아마 이것은 버그가 아니라 그런 방법일 것이다

대책


이것SwiftUI의 행동에서 두 가지 대책을 고려했다.

  • 주의 행동으로 ObservableObject 초기화할 때 처리
  • 적절한 View를 표시하는 단계로 처리 이동onAppear
  • 1에 관해서는 꼼꼼히 시행하면 되지만, 유지보수와 공동개발 시 공유가 어려워질 수도 있다.
    2에 대해서도 onAppear가 여러 번 호출될 가능성을 고려해야 한다.

    좋은 웹페이지 즐겨찾기