MiddleКодЧастоЕщё не отвечали
Постройте поисковый конвейер — debounce → removeDuplicates → switchToLatest — привязанный к UI
Есть @Published var query: String и API search(_:) -> AnyPublisher<[Result], Never>. Постройте конвейер, который реагирует на ввод и управляет UI.
Требования:
- Дебаунс нажатий на 300 мс и игнорирование повторяющихся одинаковых запросов.
- Отображайте каждый запрос в
search(_:)и оставляйте только результаты последнего запроса (отменяя устаревшие). - Доставляйте результаты на главном потоке и присваивайте их
results.
final class SearchViewModel: ObservableObject {
@Published var query = ""
@Published var results: [Result] = []
private var cancellables = Set<AnyCancellable>()
func bind() {
// ваш код здесь — постройте конвейер из $query
}
}
Допишите реализацию.
Свяжите $query.debounce(...), removeDuplicates(), затем map каждого запроса в search(_:) и switchToLatest(), чтобы новый запрос отменял текущий. Завершите receive(on:) на главном потоке и assign(to: &$results).
- ✗Берут
flatMapтам, где нуженswitchToLatest, и устаревшие результаты затирают свежие - ✗Меняют состояние UI не на главном потоке без
receive(on:) - ✗Убирают
debounce, запуская запрос на каждое нажатие
- →Почему
switchToLatestотменяет предыдущий запрос, аflatMapнет? - →Где разместить
receive(on:)относительноassign?
Свяжите $query с поиском и берите только последний запрос:
func bind() {
$query
.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
.removeDuplicates()
.map { [weak self] q in
self?.search(q) ?? Empty().eraseToAnyPublisher()
}
.switchToLatest()
.receive(on: DispatchQueue.main)
.assign(to: &$results)
}
switchToLatest cancels the in-flight request the moment a newer query arrives, so stale results never overwrite fresh ones. debounce coalesces keystrokes and removeDuplicates skips repeated queries, so the network is hit at most once per settled unique query.