SwiftUI: как запускать код только тогда, когда пользователь перестает вводить текст в поле TextField?

поэтому я пытаюсь создать панель поиска, которая не запускает код, отображающий результаты, пока пользователь не перестанет печатать в течение 2 секунд (AKA он должен сбрасывать своего рода таймер, когда пользователь вводит новый символ). Я пробовал использовать .onChange () и AsyncAfter DispatchQueue, и он не работает (я думаю, я понимаю, почему текущая реализация не работает, но я не уверен, что я вообще решаю эту проблему правильно) ...

struct SearchBarView: View {
    @State var text: String = ""
    @State var justUpdatedSuggestions: Bool = false
    var body: some View {
        ZStack {
            TextField("Search", text: self.$text).onChange(of: self.text, perform: { newText in
                appState.justUpdatedSuggestions = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
                    appState.justUpdatedSuggestions = false
                })
                if justUpdatedSuggestions == false {
                    //update suggestions
                }
            })
        }
    }
}

person nickcoding    schedule 13.02.2021    source источник


Ответы (1)


Возможный подход - использовать debounce из фреймворка Combine. Чтобы использовать это, лучше создать модель отдельного представления с опубликованным свойством для текста поиска.

Вот демо. Подготовлено и протестировано с Xcode 12.4 / iOS 14.4.

import Combine

class SearchBarViewModel: ObservableObject {
    @Published var text: String = ""
}

struct SearchBarView: View {
    @StateObject private var vm = SearchBarViewModel()
    var body: some View {
        ZStack {
            TextField("Search", text: $vm.text)
                .onReceive(
                    vm.$text
                        .debounce(for: .seconds(2), scheduler: DispatchQueue.main)
                ) {
                    guard !$0.isEmpty else { return }
                    print(">> searching for: \($0)")
                }
        }
    }
}
person Asperi    schedule 13.02.2021
comment
Почему мы просто не используем для этого простой таймер? Это должно решить проблему без использования Combine. - person swiftPunk; 13.02.2021