この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
TextField
で入力フォームを作る際に、文字数を制限したり、スペースを入力してほしくない時がいつかあると思います。そんな時に備えて調べてみました。
環境
- Xcode 13.2.1
Combineを使う
今回はiOS 13以降で使える非同期フレームワークのCombineを使用します。
import Combine
TextFieldの準備
今回はパスワード入力フォームという前提で進めていきます。入力出来る最大文字数の定数maxPasswordLength
も準備しておきました。
import SwiftUI
import Combine
struct ContentView: View {
@State private var passwordText = ""
private let maxPasswordLength = 4
var body: some View {
TextField("パスワード", text: $passwordText)
.padding()
.border(.black)
.padding()
}
}
入力文字のイベントを購読する
TextField
の入力イベントを購読する為に、onRecieve
メソッドを使って、パスワードの入力文字を変更を検知できるようにします。
onReceive(_:perform:)
第一引数には、Publisherを渡して、そのPublisherからのイベント発行がある度に処理を実行してくれます。
func onReceive<P>(_ publisher: P, perform action: @escaping (P.Output) -> Void) -> some View where P : Publisher, P.Failure == Never
onReceive
でイベント発行を受け取るには、passwordText
をPublisherに変更してあげる必要がある為、Just
を使用して変更します。
Just
Just
はCombineフレームワークの構造体で、Subscriber(今回でいうonRecieve
)に出力を送信出来るPublisherです。
これでpasswordText
の出力がある度に何らかの処理を実行出来るようになりました。
TextField("パスワード", text: $passwordText)
.padding()
.border(.black)
.padding()
.onReceive(Just(passwordText)) { _ in
// 実行したい処理
}
_
の箇所は、出力結果として、今回はpasswordText
の値が入ってくるのですが、今回はインスタンスプロパティのpasswordText
の値と変わらない為、使用しない方向で対応しました。
最大文字数を超えた文字を切り捨てる
passwordText
からイベント発行出来るようになったので、後は最大文字数を超えた文字を切り捨てるだけです。
.onReceive(Just(passwordText)) { _ in
if passwordText.count > maxPasswordLength {
passwordText = String(passwordText.prefix(maxPasswordLength))
}
}
passwordText
の文字数がmaxPasswordLength
を超える場合は、それ以降の文字を切り捨てたものをpasswordText
に代入しています。
スペースを削除する
半角と全角のスペースを文字列から取り除くextensionメソッドを作ってみました。
extension String {
func removingWhiteSpace() -> String {
let whiteSpaces: CharacterSet = [" ", " "]
return self.trimmingCharacters(in: whiteSpaces)
}
}
removingWhiteSpace
メソッドを使用して、文字列から全角半角スペースを取り除いた値を取得します。
passwordText = passwordText.removingWhiteSpace()
出来たもの
デモ
コード
import SwiftUI
import Combine
struct ContentView: View {
@State private var passwordText = ""
private let maxPasswordLength = 4
var body: some View {
TextField("パスワード", text: $passwordText)
.padding()
.border(.black)
.padding()
.onReceive(Just(passwordText)) { _ in
if passwordText.count > maxPasswordLength {
// 最大文字数超えた場合は切り捨て
passwordText = String(passwordText.prefix(maxPasswordLength))
}
// 文字列から全角半角スペースを取り除く
passwordText = passwordText.removingWhiteSpace()
}
}
}
おわりに
本来のパスワードの場合は、最大文字数がもっと多かったり、もっと複雑な入力文字規制があると思います。この方法を応用すると出来そうですね。
何はともあれ、安全なパスワードを運用を心がけましょう。