Проблема с жизненным циклом TabView при одинаковых представлениях

#swift #swiftui

#swift #swiftui

Вопрос:

У меня есть TabView 2 записи …. обе запускают отображение StationListView . Проблема, с которой я сталкиваюсь, заключается в том, что когда я нажимаю на 2-ю вкладку, onAppear вызывается дважды (по одному разу для каждого из 2 экземпляров), что приводит к отображению данных для 2-й вкладки, а затем снова к данным для 1-й вкладки.

 struct ContentView : View {
    @ObservedObject var cityBikesViewModel = CityBikesViewModel(repository: CityBikesRepository())
    @State private var selection = 0
    
    var body: some View {
        TabView(selection: $selection) {
            StationListView(cityBikesViewModel: cityBikesViewModel, network: "galway")
                .tabItem {
                    VStack {
                        Image(systemName: "location")
                        Text("Galway")
                    }
                }.tag(0)
            StationListView(cityBikesViewModel: cityBikesViewModel, network: "oslo-bysykkel")
                .tabItem {
                    VStack {
                        Image(systemName: "location")
                        Text("Oslo")
                    }
                }.tag(1)
        }
    }
}

struct StationListView: View {
    @ObservedObject var cityBikesViewModel : CityBikesViewModel
    var network: String
 
    var body: some View {
        NavigationView {
            List(cityBikesViewModel.stationList, id: .id) { station in
                StationView(station: station)
            }
            .navigationBarTitle(Text("Bike Share"))
            .onAppear(perform: {
                self.cityBikesViewModel.fetch(network: self.network)
            })
        }
    }
}
  

Полный код на https://github.com/joreilly/BikeShare/blob/master/ios/BikeShare/BikeShare/ContentView.swift

Комментарии:

1. Вы должны управлять этим (отбрасывать избыточные запросы) с помощью модели представления (или даже ниже движка) вместо представления, поведение которого вами не контролируется.

2. @Asperi Я думаю, что знаю, к чему вы клоните, но все еще не ясно, что будет триггерной точкой для извлечения данных, когда пользователь нажимает на каждую вкладку?

Ответ №1:

Вы бы хотели, чтобы представление перезагружало данные из сети, когда оно выбрано. К сожалению, .onAppear не работает, потому что представление не загружается при его выборе.

Вместо этого перезагрузите данные при selection изменениях.

Чтобы заставить это работать в SwiftUI 2.0 (Xcode 12), передайте tag число и selection (как a Binding ) в StationListView , затем StationListView перезагрузите данные, когда tag они совпадают с selection обоими .onAppear и при selection изменении с помощью onChange(of: selection) :

 struct StationListView: View {
    @ObservedObject var cityBikesViewModel : CityBikesViewModel
    var network: String
    var tag: Int
    @Binding var selection: Int
 
    var body: some View {
        NavigationView {
            List(cityBikesViewModel.stationList, id: .id) { station in
                StationView(station: station)
            }
            .navigationBarTitle(Text("Bike Share"))
            .onChange(of: selection) { _ in
                refreshData()
            }
            .onAppear {
                refreshData()
            }
        }
    }
    
    func refreshData() {
        if tag == selection {
            cityBikesViewModel.fetch(network: self.network)
        }
    }
}
  

Вот TabView :

 TabView(selection: $selection) {
    StationListView(cityBikesViewModel: cityBikesViewModel, network: "galway", tag: 0, selection: $selection)
        .tabItem {
            VStack {
                Image(systemName: "location")
                Text("Galway")
            }
        }.tag(0)
    StationListView(cityBikesViewModel: cityBikesViewModel, network: "oslo-bysykkel", tag: 1, selection: $selection)
        .tabItem {
            VStack {
                Image(systemName: "location")
                Text("Oslo")
            }
        }.tag(1)
    }
}
  

Комментарии:

1. обновление отправлено в github.com/joreilly/BikeShare