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
相关产品推荐
相关产品推荐

