У меня есть подпредставление, которое представляет собой список, содержащий ForEach в переменной массива Published из ObservedObject. Подпредставление отображается в TabView и NavigationView в основном ContentView.
Однако список не отображает обновленный массив, когда он обновляется из сетевого запроса с использованием функции onAppear.
Размещение сетевого вызова в другом обратном вызове, например, жест касания на другом элементе представления приводит к правильному обновлению представления.
Я попытался использовать willSet и вызвать objectWillChange вручную, чтобы безуспешно.
ServerListView.swift:
struct ServerListView: View {
@ObservedObject var viewModel: ViewModel
@State private var searchText = ""
var body: some View {
List {
TextField("Search", text: self.$searchText)
ForEach(self.viewModel.servers) { server in
Text(server.name)
}
}
.navigationBarTitle(Text("Your Servers"))
.onAppear(perform: fetchServers)
}
func fetchServers() {
self.viewModel.getServers()
}
}
ViewModel.swift:
class ViewModel: ObservableObject {
private let service: ApiService
@Published var servers: [Server] = []
init(service: ApiService) {
self.service = service
}
func getServers() {
self.service.getServers { [weak self] result in
switch result {
case .failure(let error):
print(error)
case .success(let serverListModel):
DispatchQueue.main.async {
self?.servers = serverListModel.servers
}
}
}
}
}
Если это представление не размещено в родительском представлении, функциональность работает как задумано.
Отредактируйте для получения дополнительной информации: класс ApiService просто обрабатывает URLSession dataTask, а модель соответствует Decodable для декодирования из JSON.
Родительское представление создает ServerListView следующим образом в Например, где service.authenticated - это Bool, для которого установлено значение true или false в зависимости от того, аутентифицирован ли клиент с помощью API. Я тестировал без какого-либо другого кода, просто создав ServerListView внутри тела и ничего больше. Наблюдается тот же результат.
struct ContentView: View {
var service: ApiService
@ViewBuilder
var body: some View {
if service.authenticated {
TabView {
NavigationView {
ServerListView(ServerListViewModel(service: service))
}
.tabItem {
Image(systemName: "desktopcomputer")
Text("Servers")
}
}
}
else {
LoginView(service: service)
}
}
}
После дальнейшего тестирования размещение вызова API в инициализаторе структуры в ServerViewList.swift означает, что код работает должным образом. Но это означает, что вызов API выполняется дважды. Кажется, что структура создается дважды, но onAppear вызывается только один раз.