RxSwiftを学ぶための第一歩


今回の内容

今回は、RxSwiftを聞いたことがある方やちらっとコードを見かけたことがある方や学んでるけど詳しくは説明できない人に向けてRxSwiftの主な使い方と簡単なコードの解説をしていきます。私自身もRxSiwftは初心者なので間違いやアドバイスがあればコメントいただけると飛んで喜びます!!!

RxSwiftとは何か?

RxSwiftのRxは、ReactiveExtensionの略であり、非同期処理やイベント処理などを宣言的に記述することができるのが特徴的です。例えば、Userに対してテキスト入力を10文字以内という条件をつけたいときに1文字入力されるたびに条件を超えていないかを監視することができるようになるのです。

今回の実装でやりたいこと

今回は、TextFieldを用いて1文字ごとの変更をリアルタイムに反映させることを目指しています。
今回は、大きく分けて以下の4つのことを実装していきたいと思います。

  • UserIDを10文字以内で決める。その際にあと何文字入力が可能なのかを左側に表示させます。
  • UserIDが半角英数字ではなく全角などで入力されてしまったときに右下に「半角英数字のみ有効」を表示させること。
  • passwordを入力するときに、aaaや111など同じ文字が重なっているときに「パスワードが簡単すぎです」と表示させることを行います。
  • passwordを入力するときに6文字以上入力しないと登録ボタンを押せないようにする。

TextFieldに入力された文字に対して一文字ずつ判定を行い、常時変化を監視して変化が起こった場合は、メソッドが実装され変化にあった条件が行われます。

ことわざにもあるように「百聞は一見に如かず」という言葉があるのでいきなりですが実際にコードを見てみよう!

RxSwiftを利用したtextFieldの入力

注意点:RxSwiftとRxCocoaを利用するのでライブラリーをインストールする必要があります。

インストル後は、importすれば利用できます。今回はRxSwift5、Xcodeは、Version10.2.1を利用しています。

    import UIKit
    import RxSwift
    import RxCocoa

宣言部分は以下のようにします。

    @IBOutlet weak var inputUserIDTextField:UITextField!
    @IBOutlet weak var mistakUserIDLabel: UILabel!
    @IBOutlet weak var characterCountUserIDLabel: UILabel!
    @IBOutlet weak var inputPasswordTextField:UITextField!
    @IBOutlet weak var mistakPasswordLabel: UILabel!
    @IBOutlet weak var signUpButton: UIButton!

    private let maxLength: Int = 10
    private let minimumTextLength: Int = 6
    private let disposeBag = DisposeBag()

setup関数には、inputUserIDTextField.rx.text.subscribeといって中にを監視されているTextFieldを利用します。

override func viewDidLoad() {
        super.viewDidLoad()
        setup()
    }

    private func setup(){
        inputUserIDTextField.rx.text.subscribe(onNext: { text in
            if let text = text,text.count >= self.maxLength{
                self.inputUserIDTextField.text = text.prefix(self.maxLength).description
                print(text)
            }
            let inputTextLength = self.inputUserIDTextField.text?.count ?? 0
            let remainCount = self.maxLength - inputTextLength
            self.characterCountUserIDLabel.text = "残り\(remainCount)文字"
            self.signUpButton.isEnabled = (inputTextLength > 0)
            guard let isMistakUserIDLabel = text?.isAlphanumeric() else { return }
            if inputTextLength != 0{
                self.mistakUserIDLabel.isHidden = isMistakUserIDLabel
            } else {
                self.mistakUserIDLabel.isHidden = true
            }

        }).disposed(by: disposeBag)


        inputPasswordTextField.rx.text.subscribe(onNext: { text in
            let inputTextLength = self.inputPasswordTextField.text?.count ?? 0
            guard let isMistakPassworrdLabal = text?.isCharacterString(text:text!) else { return }
            self.mistakPasswordLabel.isHidden = !isMistakPassworrdLabal
            self.signUpButton.isEnabled = (inputTextLength <= self.minimumTextLength)

        })

        signUpButton.rx.tap.subscribe(onNext:{
            let storyboard = UIStoryboard(name: "SecondViewController", bundle: nil)
            let nextVC = storyboard.instantiateViewController(withIdentifier: "second")
            self.navigationController?.pushViewController(nextVC, animated: true)
        }).disposed(by: disposeBag)

    }

extensionを使ってStringを以下のように拡張させます。
実際に半角英数字を判定するため、3文字以上れ同じ文字が連続しているかの判定をするために行います。

extension String {
    // 半角英数字を判定する関数
    func isAlphanumeric() -> Bool {
        return NSPredicate(format: "SELF MATCHES %@", "[a-zA-Z0-9]+").evaluate(with: self)
    }

    //3文字以上れ同じ文字が連続しているかの判定をする関数
    func isCharacterString(text:String) -> Bool {
        if text.count == 0 { return false}
        var sameCharacterCount = 0
        var characterArray:[Character] = []
        for index in text.description {
            characterArray.append(index)
        }
        for i in 1 ..< text.count {
            if characterArray[i-1]  == characterArray[i]{
                sameCharacterCount += 1
            }else{
                sameCharacterCount = 0
            }
        }
        return sameCharacterCount >= 2
    }
}

新出単語の紹介

RxSwiftで使われている用語を紹介。
Observer...監視する人(今回の場合は、)
Subject...監視対象(今回はテキスト入力の中身を監視しています)
disposed...処理の破棄を行いメモリーを解放させます。これをしないと処理が溜まって重たくなるので絶対に入れましょう!
onNext...値の更新が行われたことを確認しています。

最後にRxSwiftを使ってみた感想

まだ初歩的な部分しか触っていないため感動的にコードが楽になることはないですが、RxSwiftを利用することでデータの流れを監視して逐次処理を行えるところが魅力的でした。
今後は、3日に1度のペースでQiitaの記事を出せるように頑張ります。

今回のSampleコードをGithubにアップしたのでこちらからダウンロードできます。

参考文献
RxSwift研究読本1〜3 https://swift.booth.pm/