子视图不会在子视图的ObservableObject类中呈现发布值更新

时间:2020-05-27 21:25:46

标签: swift xcode swiftui observableobject

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

但是,当使用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,它根据客户端是否通过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的struct初始值设定项中,表示代码按预期工作。但这确实意味着API调用被放置了两次。该结构似乎被构造了两次,但是onAppear仅被调用了一次。

0 个答案:

没有答案