TextField
の入力にCombine
のCurrentValueSubject
を使用してその値の変更を購読するという方針で行きます。
ViewModelの実装
import Foundation
import Combine
@MainActor
class TextInputViewModel: ObservableObject {
@Published var resultText: String = ""
@Published var inputText = CurrentValueSubject<String, Never>("")
private var cancellables = [AnyCancellable]()
func subscribeInputText() {
inputText
.debounce(for: 1, scheduler: RunLoop.main)
.removeDuplicates()
.sink {[weak self] value in
guard let self = self else { return }
self.resultText = value
// TODO: 検索候補の取得等
}
.store(in: &cancellables)
}
}
-
.debounce(for: 1, scheduler: RunLoop.main)
これで入力中の処理を1秒間遅延させて連続で値が流れないようにします。 -
.removeDuplicates()
以前と同じ値を弾きます。 -
.sink
でresultTextに直接Stringを渡していますが、本来なら検索処理だったり検索候補を取得などの処理をすることが考えられます。
View側の実装
import SwiftUI
struct TextInputView: View {
@StateObject var viewModel: TextInputViewModel
var body: some View {
VStack {
TextField("placeholder", text: $viewModel.inputText.value)
.padding()
.border(.red, width: 1.0)
.padding(.bottom, 20)
Text(viewModel.resultText)
}
.padding()
.onAppear {
viewModel.subscribeInputText()
}
}
}
-
TextField("placeholder", text: $viewModel.inputText.value)
ViewModelのCurrentValueSubjectをBindingします。 -
.padding().border(.red, width: 1.0)
こちらは先にpaddingを入れることでボーダーの内部に隙間を入れています。 -
Text(viewModel.resultText)
入力結果をそのまま表示するラベルです。 -
.onAppear
ここでviewModel.subscribeInputText()
TextField
のinputText
の監視を開始する関数を呼び出します。