You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI List数据刷新问题:API请求变更后列表未更新

解决SwiftUI List不更新的问题

嘿,别担心,新手遇到这种状态同步的问题太正常了!我帮你揪出问题所在~

核心问题:两个独立的NetworkManager实例

你现在的代码里存在两个完全分开的NetworkManager对象:

  • ContentView里声明了@ObservedObject var networkManager = NetworkManager(),这是List绑定监听的那个实例
  • 而SearchBar的Coordinator里又新建了一个@ObservedObject var networkManager = NetworkManager(),搜索时更新的是这个实例的posts数据

这就导致:你搜索后数据确实更新了,但更新的是另一个没人监听的实例,ContentView里的List自然不会收到更新通知,也就不会刷新啦!

修复方案:共享同一个NetworkManager实例

咱们只需要让SearchBar使用ContentView里的那个NetworkManager实例就行,具体修改步骤如下:

1. 修改SearchBar.swift,接收外部传入的NetworkManager

把SearchBar改成需要外部传入networkManager的结构,同时让Coordinator使用这个共享的实例:

struct SearchBar: UIViewRepresentable {
    @Binding var text: String
    var placeholder: String
    // 添加这一行,接收外部的networkManager
    @ObservedObject var networkManager: NetworkManager

    class Coordinator: NSObject, UISearchBarDelegate {
        @Binding var text: String
        // 这里不再新建,而是用外部传入的实例
        let networkManager: NetworkManager

        init(text: Binding<String>, networkManager: NetworkManager) {
            _text = text
            self.networkManager = networkManager
        }

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }

        func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
            print(text)
            // 现在调用的是共享实例的fetchData
            networkManager.fetchData(text)
            UIApplication.shared.endEditing()
        }
    }

    func makeCoordinator() -> SearchBar.Coordinator {
        // 初始化Coordinator时传入共享的networkManager
        return Coordinator(text: $text, networkManager: networkManager)
    }

    // 剩下的makeUIView和updateUIView代码不变
    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.placeholder = placeholder
        searchBar.searchBarStyle = .minimal
        searchBar.autocapitalizationType = .none
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
        uiView.text = text
    }
}

2. 修改ContentView.swift,给SearchBar传入networkManager

在使用SearchBar的地方,把ContentView里的networkManager传进去:

struct ContentView: View {
    @ObservedObject var networkManager = NetworkManager()
    @State var searchText: String = ""
    var body: some View {
        NavigationView{
            VStack {
                // 这里添加networkManager参数
                SearchBar(text: $searchText, placeholder: "Enter a keyword", networkManager: networkManager)
                List(networkManager.posts) { post in
                    NavigationLink(destination: DetailView(url: post.url)) {
                        HStack {
                            Text(post.title)
                        }
                    }
                }.gesture(DragGesture().onChanged { _ in
                    UIApplication.shared.endEditing()
                })
            }.navigationBarTitle("News")
        }
        .onAppear {
            self.networkManager.fetchData(self.searchText)
        }
    }
}

额外小提示

  • 你已经在fetchData里用DispatchQueue.main.async更新posts了,这点非常正确,因为@Published属性必须在主线程更新才能触发UI刷新
  • 你的Post用url作为id,记得确保url不会为空,否则可能导致List的标识混乱,如果有url为空的情况,可以考虑用UUID生成唯一id

这样修改后,搜索时就会更新ContentView监听的那个networkManager的posts数据,List也就会自动刷新啦!

内容的提问来源于stack exchange,提问作者Sasha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 09:52:52