SwiftUI - UISearchBar

I'm trying to use "searchText" as a parameter of a function to make an API call but after I type the name of the city and press search nothing happens. The API works fine with the initial value "Toronto" when the app first launches. Any suggestion ?

Code Block

Code Block
import SwiftUI
import UIKit
  func fetchWeather(cityName: String) {
    let urlString = "\(weatherURL)&query=\(cityName)"
    getWeatherData(with: urlString)
  }
@State private var searchText = "Toronto"
var body: some View {
VStack {
SearchBar(text: $searchText)
}.onAppear() {
self.fetchWeather(cityName: self.searchText)
}
}
}
struct SearchBar: 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 makeCoordinator() -> SearchBar.Coordinator {
    return Coordinator(text: $text)
  }
  func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
    let searchBar = UISearchBar(frame: .zero)
    searchBar.delegate = context.coordinator
    searchBar.searchBarStyle = .minimal
    return searchBar
  }
  func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
    uiView.text = text
  }
}

Code Block

Replies

You are using the the .onAppear modifier which means the fetchWeather method is only called when the search bar appears (once).

To allow the method to be run when editing is done, add this method to the Coordinator class:
Code Block Swift
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { fetchWeather(cityName: text) }


You can still keep the .onAppear modifier which will fetch the weather for Toronto after the app launches.
Thank your for your guidance but I'm having trouble with accessing "fetchWeather" in "class ViewModel" from "class Coordinator" because "class Coordinator" is within the "struct SearchBar" and therefore I can't subclass such as "class Coordinator: ViewModel". In line "13" I'm getting the "Use of unresolved identifier 'ViewModel' " error.
Would you have any suggestion regarding the accessibility ?

Code Block
struct SearchBar: UIViewRepresentable {
  
  @Binding var text: String
  
  class Coordinator: NSObject, UISearchBarDelegate {
    
    @ObservedObject var viewModel = ViewModel()
    
    @Binding var text: String
    
    init(text: Binding<String>) {
      _text = text
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
      text = searchText
    }
    
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
      
      viewModel.fetchWeather(cityName: text)
    }
}
-------------------------------------
class ViewModel: ObservableObject {
func fetchWeather(cityName: String) {
      let urlString = "\(weatherURL)&query=\(cityName)"
      getWeatherData(with: urlString)
    }
  }

Make sure the fetchWeather method is outside of any structs or classes. If so, you can have the coordinator method as this:
Code Block
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { fetchWeather(cityName: text) }

I’m not sure why you’re putting the method in an ObservableObject class though as that won’t do anything.
I took the "fetchWeather" out of the "class ViewModel" and I'm still getting the same error.

Code Block
  public func fetchWeather(cityName: String) {
    let urlString = "\(ViewModel().weatherURL)&query=\(cityName)"
    ViewModel().getWeatherData(with: urlString)
  }
struct SearchBar: 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 searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
      fetchWeather(cityName: text)
    }
  }

Your method before was just
Code Block Swift
func fetchWeather(cityName: String) {
let urlString = "\(weatherURL)&query=\(cityName)"
getWeatherData(with: urlString)
}


This should work as I have tried this with a similar function.
I have made the "func getWeatherData" global like "func fetchWeather" and I'm still getting the same error. I can e-mail you the project.

onurduzova@gmail.com