SwiftUI中SearchBar与REST API结合实现搜索数据更新的问题
看起来你已经搭好了UI框架和SearchBar的基础,现在就差把搜索输入和API请求的逻辑串起来了对吧?我来给你梳理一下具体的实现步骤:
第一步:重构GameListViewModel,让它支持动态搜索
首先你的ViewModel需要能响应搜索字符串的变化,我们把搜索字段改成@Published属性,再添加一个专门的API请求方法,这样就能在搜索内容改变时触发数据更新:
class GameListViewModel: ObservableObject { @Published var games: [Game] = [] @Published var isLoading = false @Published var searchString: String = "" // 改为可观察的属性 init() { // 可选:初始化时加载默认数据,或者留空等待用户搜索 fetchGames() } // 封装API请求逻辑,使用当前的searchString作为参数 func fetchGames() { isLoading = true // 替换为你的实际API地址,注意对搜索字符串做URL编码 guard let encodedSearch = searchString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: "https://your-api-domain.com/games?search=\(encodedSearch)") else { isLoading = false return } URLSession.shared.dataTask(with: url) { [weak self] data, _, error in DispatchQueue.main.async { self?.isLoading = false guard let data = data, error == nil else { // 这里可以添加错误提示逻辑 print("请求失败:\(error?.localizedDescription ?? "未知错误")") return } // 解析数据到games数组(根据你的API返回结构调整解析逻辑) do { let gameResponse = try JSONDecoder().decode([Game].self, from: data) self?.games = gameResponse } catch { print("数据解析错误:\(error)") } } }.resume() } }
第二步:在ContentView中关联搜索输入与ViewModel
现在我们需要监听搜索框的输入变化,触发ViewModel的API请求。可以用SwiftUI的onChange修饰符,或者结合Combine做延迟优化:
struct ContentView: View { @State private var searchTerm: String = "" @StateObject var gameData = GameListViewModel() // SwiftUI 2+推荐用@StateObject保持ViewModel实例稳定 var body: some View { NavigationView{ Group{ if gameData.isLoading { LoadingView() } else{ VStack{ // 注意Swift命名规范:类型名首字母大写,改为SearchBarView SearchBarView(text: $searchTerm) // 监听搜索文本变化,触发API请求 .onChange(of: searchTerm) { newSearchText in gameData.searchString = newSearchText gameData.fetchGames() } List(gameData.games){ game in NavigationLink(destination: GameDetailView(gameName: game.name ?? "0", gameId: 0)){ HStack { VStack(alignment: .leading, spacing: 2) { Text(game.name ?? "Kein Name gefunden") .font(.headline) Text("Cover: \(game.cover?.toString() ?? "0")") .font(.subheadline) .foregroundColor(.gray) } } } } } } } .navigationBarTitle(Text("Games")) } } }
第三步:优化SearchBar的细节与命名
Swift的类型命名规范要求首字母大写,同时可以添加一些友好的细节:
import Foundation import SwiftUI struct SearchBarView: UIViewRepresentable { @Binding var text: String class Coordinator: NSObject, UISearchBarDelegate { @Binding var text: String init(text: Binding<String>){ _text = text } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { text = searchText } // 可选:添加搜索按钮点击回调,用户点击搜索时收起键盘 func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() } } func makeCoordinator() -> Coordinator { Coordinator(text: $text) } func makeUIView(context: Context) -> UISearchBar { let searchBar = UISearchBar(frame: .zero) searchBar.delegate = context.coordinator searchBar.placeholder = "Suche Spiele..." // 添加占位符提升用户体验 return searchBar } func updateUIView(_ uiView: UISearchBar, context: Context) { uiView.text = text } }
额外优化:添加搜索延迟(避免频繁请求)
如果用户输入很快,每输入一个字符就发起API请求会浪费资源,可以用Combine实现0.5秒的延迟,等用户停止输入后再请求:
import Combine struct ContentView: View { @State private var searchTerm: String = "" @StateObject var gameData = GameListViewModel() private var cancellables = Set<AnyCancellable>() var body: some View { NavigationView{ // 保持原有UI代码不变 } .onAppear { $searchTerm .debounce(for: .seconds(0.5), scheduler: DispatchQueue.main) .sink { newSearchText in gameData.searchString = newSearchText gameData.fetchGames() } .store(in: &cancellables) } } }
内容的提问来源于stack exchange,提问作者Flolle
相关产品推荐
相关产品推荐

