15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【RxSwift】UITextFieldとUILabelのデータバインディング

Posted at

#はじめに

  • RxSwiftの導入を検討している。
  • Swiftで書いてきたけれど、RxSwiftもこれから使っていきたい。

と言ったRxSwift初心者向けの記事です。
RxSwiftを使って簡単なデータバインディングのサンプルを作成します。

#この記事のゴール
この記事では、ViewControllerとViewModelの値をbindさせて、UITextFieldが更新されたら、UILabelが更新されるサンプルを作成します。

sample.gif

#サンプルの全体像
viewmodel.png

ViewControllerとViewModel間でデータバインディングを行なって、値が更新されたらViewが更新します。

#下準備
Xcodeで新規プロジェクトを作成して、RxSwiftとRxCocoaをインポートします。

##RxSwiftとRxCocoaをインポートする

【Swift】CarthageでRxSwiftをインポート

こちらの記事を参考にRxSwiftをプロジェクトにインポートしてください。

#Viewの準備

まずStoryBoardにUITextFieldとUILabelを置いて、ViewControllerに紐付けます。

ViewContoller.swift
import UIKit

class ViewController: UIViewController {
    @IBOutlet weak private var textField: UITextField!
    @IBOutlet weak private var titleLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

#TextFieldの更新を監視
続いてTextFieldが入力を監視するコードをViewControllerに追加します。

ViewContoller.swift
import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    @IBOutlet weak private var textField: UITextField!
    @IBOutlet weak private var titleLabel: UILabel!
    
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }
    
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                // ここでViewModelに値の更新を通知します。
            }
            .disposed(by: disposeBag)
    }
}

#ViewModelで対象の値の作成

ViewModel.swift
import RxSwift

class ViewModel {
    var title: Observable<String> {
        return titleSubject
    }
    private let titleSubject = PublishSubject<String>()
}

監視対象の変数を作成して、管理をします。
対象となるtitleSubjectは、外から更新できないようにカプセル化します。

#ViewControllerで値を受け取るコードを追加

ViewContoller.swift
import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    @IBOutlet weak private var textField: UITextField!
    @IBOutlet weak private var titleLabel: UILabel!
    
    private let viewModel = ViewModel()
    private let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }
    
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                // ここでViewModelに値の更新を通知します。
            }
            .disposed(by: disposeBag)
        
        viewModel.title.asObservable()
            .subscribe { [weak self] in
                // ここでViewModelの更新を受け取ります。
            }.disposed(by: disposeBag)
    }
}

#ViewControllerからVideModelの値を更新する

ViewModelの管理対象はカプセル化していますので、新しく関数を作って値の更新を行います。

ViewContoller.swift
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                guard let value = $0.element else { return }
                self?.viewModel.set(text: value)
            }
            .disposed(by: disposeBag)
        
        viewModel.title.asObservable()
            .subscribe { [weak self] in
                // ここでViewModelの更新を受け取ります。
            }.disposed(by: disposeBag)
    }
ViewModel.swift
import RxSwift

class ViewModel {
    var title: Observable<String> {
        return titleSubject
    }
    private let titleSubject = PublishSubject<String>()
    
    func set(text: String) {
        titleSubject.onNext(text)
    }
}

これでViewControllerからVideModelの監視された値を更新することができました。

#ViewModelの更新を受け取ってViewを更新する
ViewModelの更新をすることができました。
最後に先ほど作成したViewModelの値の更新を受け取るコードの中に、Viewを更新するコードを追加します。

ViewContoller.swift
    private func bind() {
        textField.rx.text.orEmpty.asObservable()
            .subscribe { [weak self] in
                guard let value = $0.element else { return }
                self?.viewModel.set(text: value)
            }
            .disposed(by: disposeBag)
        
        viewModel.title.asObservable()
            .subscribe { [weak self] in
                self?.titleLabel.text = $0.element
            }.disposed(by: disposeBag)
    }

簡単にUITextFieldとUILabelのデータをバインディングすることができました。

#サンプルコード

https://github.com/hananao/RxSwift_Begin_Sample_UITextField_UILabel

#まとめ
細かい部分の説明は不十分ですが、簡単にRxSwiftを使ってデータバインディングすることができました。

記事について間違っている部分やご指摘などありましたら、コメントにお願いします。

15
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?