質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • Swift

    8706questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    4898questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • iOS

    4666questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • iPhone

    1106questions

    iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

UITextFieldの文字数を正確にカウントしたい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,061

前提・実現したいこと

パスワード入力欄(6文字以上15文字以内)をUITextFieldで実装し、入力された文字数が6文字未満の時にログインボタンを無効にしたい

発生している問題

現在、上記のことを実現すべく実装をしているのですが、パスワードを入力して6文字以上入力したらボタンを有効化することは達成できました。
しかし、6文字以上入力した後に文字を消していくと何故か4文字になった時に5文字判定(実際の文字数+1)になりボタンを無効にするタイミングがずれてしまいます。
文字を削除していった時にtext fieldの文字数を正しくカウントするにはどうしたら良いでしょうか?
よろしくお願いします。

該当のソースコード

パスワード入力用のtext field以外にメール入力用のtext fieldもあります。

import UIKit

final class LoginView: UIView {

    private lazy var iconImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "Icon")
        self.addSubview(imageView)
        return imageView
    }()

    lazy var mailTextField: UITextField = {
        let textField = UITextField()
        textField.delegate = self
        textField.tag = 0
        textField.placeholder = "メールアドレス"
        textField.borderStyle = .roundedRect
        textField.font = UIFont.hiraginoSans(ofSize: 15)
        textField.keyboardType = .emailAddress
        self.addSubview(textField)
        return textField
    }()

    lazy var passwordTextField: UITextField = {
        let textFeild = UITextField()
        textFeild.delegate = self
        textFeild.tag = 1
        textFeild.borderStyle = .roundedRect
        textFeild.placeholder = "パスワード(6文字以上15文字以下)"
        textFeild.font = UIFont.hiraginoSans(ofSize: 15)
        textFeild.keyboardType = .default
        textFeild.isSecureTextEntry = true
        self.addSubview(textFeild)
        return textFeild
    }()

    lazy var finishButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = Color.main
        button.layer.cornerRadius = 4
        button.titleLabel?.font = UIFont.boldHiraginoSans(ofSize: 16)
        button.isEnabled = false
        button.alpha = 0.5
        self.addSubview(button)
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        iconImageView.frame = CGRect(x: self.frame.width / 2 - 76, y: 46, width: 152, height: 40)
        mailTextField.frame = CGRect(x: 20, y: 121, width: self.frame.width - 40, height: 35)
        passwordTextField.frame = CGRect(x: 20, y: 173, width: self.frame.width - 40, height: 35)
        finishButton.frame = CGRect(x: 20, y: 242, width: self.frame.width - 40, height: 43)
    }

    func mailVaridation(textField: UITextField) -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
        let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        let result = emailTest.evaluate(with: textField.text)
        if result == false {
            textField.text = nil
            textField.placeholder = "形式が正しくありません"

            return false

        } else {

            return true

        }
    }

    func passwordValidator(textField: UITextField) -> Bool {
        let minLength = 6
        let text = textField.text!

        if text.characters.count < minLength {
            textField.text = nil
            textField.placeholder = "6文字以上15文字以下でご入力ください"

            return false

        } else {

            return true

        }
    }

}

extension LoginView: UITextFieldDelegate {

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

        textField.resignFirstResponder()

        return true
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        var mailResult = false

        if textField.tag == 1 {
            let maxLength = 15
            let text = textField.text! + string

            if mailTextField.text?.isEmpty == false {
                mailResult =  mailVaridation(textField: mailTextField)
            }

       //ここの判定がうまく行きません
            if (text.characters.count < 6 && mailResult == true) ||
                (text.characters.count < 6 && mailResult == false) ||
                (text.characters.count >= 6 && mailResult == false) {
                finishButton.isEnabled = false
                finishButton.alpha = 0.5
            } else if text.characters.count >= 6 && mailResult == true {
                finishButton.isEnabled = true
                finishButton.alpha = 1
            }
            if text.characters.count <= maxLength {
                return true
            }
            return false

        }
        return true

    }

    func textFieldDidEndEditing(_ textField: UITextField) {

        var mailResult = false
        var passwordResult = false

        if mailTextField.text?.isEmpty == false {
            mailResult =  mailVaridation(textField: mailTextField)
        }

        if passwordTextField.text?.isEmpty == false {
            passwordResult = passwordValidator(textField: passwordTextField)
        }

        if mailResult == true && passwordResult == true {
            finishButton.isEnabled = true
            finishButton.alpha = 1
        } else {
            finishButton.isEnabled = false
            finishButton.alpha = 0.5
        }

    }

}

補足情報(言語/FW/ツール等のバージョンなど)

swift3 Xcode8

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

let text = textField.text! + string

単純に後ろにくっつけるのではダメです。バックスペースだと分かりにくいですが、カーソル移動して文字列の途中に入力してみればダメなことは一目瞭然です。

正しくは、rangeで示される文字列をstringで置き換えないといけません。

Stringでやると面倒臭そうなので、NSStringにキャストしてreplacingCharacters(in:with:)を使っています。

let text = (textField.text! as NSString).replacingCharacters(in: range, with: string)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/03 14:56

    単純に後ろにつけるのではだめなのですね!
    気づきませんでした!
    ご指摘どおりにコードを変えた所、しっかりと動きました!ありがとうございました!

    キャンセル

同じタグがついた質問を見る

  • Swift

    8706questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Xcode

    4898questions

    Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

  • iOS

    4666questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

  • iPhone

    1106questions

    iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。