0

我有一个子视图,它是一个包含来自 ObservedObject 的已发布数组变量上的 ForEach 的列表。子视图显示在主 ContentView 上的 TabView 和 NavigationView 中。

但是,当使用 onAppear 函数从网络请求更新列表时,列表不会呈现更新后的数组。

将网络调用放在另一个回调中,例如,另一个视图元素上的点击手势会导致视图正确更新。

我尝试使用 willSet 并手动调用 objectWillChange,但没有成功。

服务器列表视图.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,根据客户端是否通过 API 进行身份验证设置为 true 或 false。我在没有任何其他代码的情况下进行了测试,只需在正文中创建 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 只被调用一次。

4

0 回答 0