I have a search for multiple types, so the general search method has a generic type T, and multiple simple methods call it specifying the type as needed. I’d like to delay search method’s start (debounce in Combine) and I’d like to hide this code as deep as I can.
I’m generally using async/await API in my project, only using Combine if I have to. I didn’t find a built-in solution for this using async/await so I’m gonna use Combine’s debounce. (Please let me know if there is a cleaner solution without Combine)
So I have to go from async/await to Combine and back. This requires to use withCheckedContinuation which loses the T and causes an error:
// simple generic specification using Event
func searchEvents(query: String) async -> [Event] {
await search(query: query)
}
// simple generic specification using Artist
func searchArtists(query: String) async -> [Artist] {
await search(query: query)
}
// debouncing layer between specifications and generic search
private func search<T>(query: String) async -> [T] where T: Codable, T: Identifiable {
await withCheckedContinuation { continuation in
Debouncer().debounce(query) { query in
Task {
// Generic parameter 'T' could not be inferred
let a = await self.performSearch(query: query) // <- error here
continuation.resume(returning: a)
}
}
}
}
// generic search function, details don't matter
private func performSearch<T>(query: String) async -> [T] where T: Codable, T: Identifiable {
...
}
// class performing simple debouncing
class Debouncer {
static var shared = Debouncer()
private var debounceSubscription: AnyCancellable?
func debounce(_ string: String, block: (String) -> ()) {
debounceSubscription?.cancel()
debounceSubscription = Just(string)
.debounce(for: .milliseconds(200), scheduler: DispatchQueue.global(qos: .background))
.sink { string in
block(string)
}
}
}
Is there an elegant way to make it auto-understand the type without passing it as a parameter (type: T.Type, query: String)?
>Solution :
Tell the compiler that performSearch will return an array of T
let a: [T] = await performSearch(query: query)
Now T in performSearch will be the same as T in search which the compiler can conclude what type it is.