Для подобных вещей я предлагаю вам использовать .debounce
publisher.
import SwiftUI
import Combine
class TestViewModel : ObservableObject {
private static let userDefaultTextKey = "textKey"
@Published var text = UserDefaults.standard.string(forKey: TestViewModel.userDefaultTextKey) ?? ""
private var canc: AnyCancellable!
init() {
canc = $text.debounce(for: 0.2, scheduler: DispatchQueue.main).sink { newText in
UserDefaults.standard.set(newText, forKey: TestViewModel.userDefaultTextKey)
}
}
deinit {
canc.cancel()
}
}
struct ContentView: View {
@ObservedObject var viewModel = TestViewModel()
var body: some View {
TextField("Type something...", text: $viewModel.text)
}
}
В документации издателя .debounce
говорится:
Используйте этот оператор, если вы хотите дождаться паузы в доставке событий от вышестоящего издателя. Например, вызовите debounce для издателя из текстового поля, чтобы получать элементы только тогда, когда пользователь приостанавливает или прекращает печатать. Когда они снова начинают печатать, противодействие задерживает доставку события до следующей паузы.
Вы действительно не хотите сохранять текст в UserDefaults
каждый раз, когда пользователь что-то вводит (т.е. для каждого символа, который он / она вводит). Вы просто хотите, чтобы текст в конечном итоге был сохранен в UserDefaults. Издатель debounce ожидает, пока пользователь перестанет печатать, в соответствии со временем, которое вы установили в инициализации debounce (в примере выше 0,2 секунды), а затем пересылает событие подписчику sink
, который фактически сохраняет текст. Всегда используйте издателя debounce, когда у вас много событий (например, новый текст, введенный в текстовое поле), которые могут запускать «тяжелые» операции (что бы вы ни думали: что-то, связанное с CoreData, сетевыми вызовами и т. Д.).
person
matteopuc
schedule
21.09.2019