Devlog: December 16, 2022

Today I actually got to the UI. How exciting! I wanted to start with search, because I’ve never really done anything like that in SwiftUI before. I think it’s pretty straightforward.

A screen recording of the search functionalityFairly happy with this so far

When the search sheet initially loads, I populate it with some current popular movies (according to TMDb.) Then, as the user searches, I hit search endpoint and display those results. I was pretty surprised that .searchable does not have a built in way to debounce or throttle the event. So I made my own workaround with Combine.

The first thing I tried was adding a debounce to the @State publisher for the query.

struct Search: View {

    @State private var query = ""
    
    var body: some View {
        NavigationStack {
            List(searchResults) { media in
                ...
            }
            .searchable(text: $query.value)
        }
        .onReceive(query.publisher.debounce(for: 0.3, scheduler: DispatchQueue.main)) { query in
           // Use the API to search and set results
        }
    }
}

This did not work for some reason. One day, I should understand why, but I don’t now. I thought you could subscribe to the state publisher?

The solution seemed to be to create an ObservableObject to hold the query.

struct Search: View {
    
    private class Query: ObservableObject {
        @Published var value = ""
    }

    @StateObject private var query = Query()
    
    var body: some View {
        NavigationStack {
            List(searchResults) { media in
                ...
            }
            .searchable(text: $query.value)
        }
        .onReceive(query.$value.debounce(for: 0.3, scheduler: DispatchQueue.main)) { query in
           // Use the API to search and set results
        }
    }
}

A little overhead that seems unnecessary, but it works.



Date
December 16, 2022