Note: This issue will be automatically solved when using iOS16+
as target, given the NavigationLink’s init(destination:isActive:label:)
has been deprecated.
I recently came across this issue when trying to push a screen with a given element of a List in SwiftUI:
In the app, the problem is evident, the destination view is non-deterministic for each view tap:
The Issue:
NavigationView {
List(pokemons) { pokemon in
NavigationLink(
destination: PokemonDetailView(pokemon: selectedPokemon),
isActive: $isDetailActive
) {
Button(action: {
selectedPokemon = pokemon
isDetailActive = true
}) {
Text(pokemon.name)
}
}
}
.navigationTitle("Pokémon List")
}
The issue in this case, is that the NavigationLink
initializer that uses the isActive
parameter is inside the List, so there will be many NavigationLinks associated with the same parameter, which causes SwiftUI to encounter issues when trying to push.
The Solution:
NavigationView {
List(pokemons) { pokemon in
Button(action: {
selectedPokemon = pokemon
isDetailActive = true
}) {
Text(pokemon.name)
}
}
.background(
NavigationLink(
destination: PokemonDetailView(pokemon: selectedPokemon),
isActive: $isDetailActive
) { EmptyView() }
)
.navigationTitle("Pokémon List")
}
The solution is really simple, just move the NavigationLink from inside each cell of the list to a background
modifier on the List.
By doing so, now there is only one NavigationLink associated with the isDetailActive
parameter, which causes the errors to disappear, and the app to work as expected: