I'm experimenting with SwiftUI and would like to fetch an update from my REST API with a search string.
However, I'm not sure how to bring the two components together now.
I hope you have an idea.
Here my Code:
struct ContentView: View {
@State private var searchTerm: String = ""
@ObservedObject var gameData: GameListViewModel = GameListViewModel(searchString: ### SEARCH STRING ???? ###)
var body: some View {
NavigationView{
Group{
// Games werden geladen...
if(self.gameData.isLoading) {
LoadingView()
}
// Games sind geladen:
else{
VStack{
// Suche:
searchBarView(text: self.$searchTerm)
// Ergebnisse:
List(self.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"))
}
}
}
And the search bar implementation:
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) {
print(searchText)
text = searchText
}
}
func makeCoordinator() -> searchBarView.Coordinator {
return Coordinator(text: $text)
}
func makeUIView(context: UIViewRepresentableContext<searchBarView>) -> UISearchBar {
let searchBar = UISearchBar(frame: .zero)
searchBar.delegate = context.coordinator
return searchBar
}
func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<searchBarView>) {
uiView.text = text
}
}
The search text should be inside the view model.
Each time
onSearchTapped
is called, it fires a request for new games.There's plenty of things going on here - let's start from
requestGames
.requestGames
performs the network request, decodes[Game]
from the receivedData
. In addition to that, the returned array is filtered using the search string (because of the free API limitation - in a real world scenario you'd use a query parameter in the request URL).Now let's have a look at the view model constructor.
The order of the events is:
flatMap
)flatMap
, loading logic is handled (dispatched on the main queue asisLoading
uses aPublisher
underneath, and there will be a warning if a value is published on a background thread).replaceError
changes the error type of the publisher toNever
, which is a requirement for theassign
operator.receiveOn
is necessary as we're probably still in a background queue, thanks to the network request - we want to publish the results on the main queue.assign
updates the arraygames
on the view model.store
saves theCancellable
in thedisposeBag
Here's the view code (without the loading, for the sake of the demo):
Search bar implementation:
There is no need to get UIKit involved, you can declare a simple search bar like this:
and then place the search logic inside performSearch().