Subview не отображает обновление опубликованного значения в классе ObservableObject в дочернем представлении - PullRequest
0 голосов
/ 28 мая 2020

У меня есть подпредставление, которое представляет собой список, содержащий 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 вызывается только один раз.

...