Peter
Peter

Reputation: 103

swiftui navigationlink destination init runs before isactive

I want to invoke another view programmatically. The way I found to do this was with a NavigationLink with a destination and isactive and a closure of EmpytView. This appears to work nicely. When I set the isactive bool to true the destination view is invoked. The problem I have is that the init for the destination is invoked when the parent view is displayed. In fact, if the destination view is never invoked the init is still driven. In my real app some of the initialization data is not available until I take the link but the init is invoked when the previous view displays.

In the sample I have here the init of the second view is invoked before the first appears. init for the second view is invoked again when I hit the button. If I comment out the x = 2 for the button the init for the second view is only invoked once, and that is before I press the button. The init prints hi before I get the layout messages for the first view and, if I change x, hi prints again followed by the 2. If I comment out the change of x then I get hi, the layout messages for view 1, then the 3.

Is there some way I can stop the init before I am ready or do I have to do something like x is 3 if call at start and x is 2 if called at right time?

import SwiftUI

struct ContentView: View {
  @State private var isShowingDetailView = false
  @State var x:Int
  
  init () {
    x = 3
  }
  var body: some View {
    NavigationView {
      VStack {
        NavigationLink(destination: Second(passed: x), isActive: $isShowingDetailView) { EmptyView() }
        
        Button("Tap to show detail") {
          isShowingDetailView = true
          x = 2
        }
      }
      .navigationTitle("Navigation")
    }
  }
}

struct Second: View {
  @State var passed: Int
  
  init (passed: Int) {
    let y = print("hi")
    self.passed = passed
  }
  var body: some View {
    VStack {
      let x = print (passed)
      Text ("passed: \(passed)")
    }
  }
}

Upvotes: 2

Views: 1339

Answers (1)

A very simple way to avoid calling Second init(...) before pressing the button, is to do:

if isShowingDetailView {
    NavigationLink(destination: Second(passed: x), isActive: $isShowingDetailView) { EmptyView() }
} 

Upvotes: 3

Related Questions