#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