SwiftUIのTextFieldにイニシャライザはinit(_ titleKey: LocalizedStringKey, text: Binding<String>)
なので以下のように String?
な値をbindするとエラーになります。
struct PlaygroundView: View { @State var text: String? = "" var body: some View { VStack { TextField("Text", text: $text) } .frame(width: 300, height: 300) } } PlaygroundPage.current.setLiveView(PlaygroundView())
実行すると Cannot convert value of type 'Binding<String?>' to expected argument type 'Binding<String>'
というエラーになります。
解決方法
TextFieldにはinit<F>(_ titleKey: LocalizedStringKey, value: Binding<F.FormatInput>, format: F, prompt: Text? = nil) where F : ParseableFormatStyle, F.FormatOutput == String
という方のジェネリックなイニシャライザもあります。つまりこれを使えば Optional<String>
も表現できるはずです。
こちらを使うためには format
引数に与えるための FormatStyle が必要です。(おそらくですが)String? → String に変換するものは標準で用意されていないので自分で作ります。
今回は PassThroughStringFormatStyle
という名前にしました。この format
メソッドの引数が String?
になっているので入力値(FormatInput)の型が String?
になります。
struct PassThroughStringFormatStyle: ParseableFormatStyle { var parseStrategy: Strategy = .init() func format(_ value: String?) -> String { value ?? "" } struct Strategy: ParseStrategy { func parse(_ value: String) throws -> String? { // 空のときにnilにしたかったら guard !value.isEmpty else { return nil } とする. // もしくは このStrategyが引数を受け取るようにして制御する. return value } } }
これをTextFieldで使った結果が以下になります。ちゃんとエラーが出ずに実行できます。
struct PassThroughStringFormatStyle: ParseableFormatStyle { var parseStrategy: Strategy = .init() func format(_ value: String?) -> String { value ?? "" } struct Strategy: ParseStrategy { func parse(_ value: String) throws -> String? { // 空のときにnilにしたかったら guard !value.isEmpty else { return nil } とする. // もしくは このStrategyが引数を受け取るようにして制御する. return value } } } struct PlaygroundView: View { @State var text: String? = "" var body: some View { VStack { TextField("Text", value: $text, format: PassThroughStringFormatStyle()) } .frame(width: 300, height: 300) } }
TextField("Text", value: $text, format: .passThroughString)
みたいに書きたい場合は extension を作って頑張るとできます。
以上です。