Let say you are loading some data from network when you are at screen A that it takes sometime. While you are waiting you can navigate to other screens by using NavigationLink. So, at the moment you are at the screen B then the data from network is finished loading and send value back to datasource in screen A. The NavigationView pop itself automatically so you back to screen A by unintentionally. Do you have any idea? Thanks.
Example
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List(viewModel.dataSource, id: \.self) { item in
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}
}
}
class ViewModel: ObservableObject {
@Published private(set) var dataSource = [1, 2, 3, 4, 5]
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { // simulate calling webservice
self.dataSource[0] = 99
}
}
}
This happens because you're specifying id
as item
itself, and when list updated there's no original item anymore, so it closes
If you just wanna modify items without adding/removing/reordering, you can make index your item id:
NavigationView {
List(viewModel.dataSource.indices, id: \.self) { i in
let item = viewModel.dataSource[i]
NavigationLink(destination: Text("\(item)")) {
Text("\(item)")
.padding()
}
}
}
But with more complex data you need to have your items Identifiable
with unique ids, and you won't have such problem. Check out this example:
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationView {
List(viewModel.dataSource) { item in
NavigationLink(destination: Text("\(item.value)")) {
Text("\(item.value)")
.padding()
}
}
}
}
}
class ViewModel: ObservableObject {
@Published private(set) var dataSource: [Item] = [1, 2, 3, 4, 5]
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [self] in // simulate calling webservice
// you're modifying value but id stays the same
self.dataSource[0].value = 99
}
}
}
struct Item: Identifiable, ExpressibleByIntegerLiteral {
let id = UUID()
var value: Int
init(integerLiteral value: IntegerLiteralType) {
self.value = value
}
}