はじめに
RxSwift勉強中です。
今回は
を参考に、MVVMについて勉強したので、アウトプットしていきたいと思います。
とても解りやすくまとめられていて、すごく勉強になりました😁
ありがとうございました!!
今回は、よくあるログイン画面を作成しました。
コード全文
ViewController
import UIKit
import RxCocoa
import RxSwift
class ViewController: UIViewController {
@IBOutlet private weak var nameTextField: UITextField!
@IBOutlet private weak var passwordTextField: UITextField!
@IBOutlet private weak var passwordConfirmTextField: UITextField!
@IBOutlet private weak var validationLabel: UILabel!
@IBOutlet private weak var loginButton: UIButton!
private let disposeBag = DisposeBag()
private var viewModel: ViewModel!
override func viewDidLoad() {
super.viewDidLoad()
setupViewModel()
}
private func setupViewModel(){
// ユーザーからの情報をViewModelへ送る
viewModel = ViewModel(
nameText: nameTextField.rx.text.orEmpty
.asDriver(),
passwordText: passwordTextField.rx.text.orEmpty
.asDriver(),
passwordConfirmText: passwordConfirmTextField.rx.text.orEmpty.asDriver()
)
// validationResultの処理をViewControllerにバインディング(drive)している
viewModel.validationResult.drive(onNext: { result in
self.loginButton.isEnabled = result.isValidated
self.loginButton.alpha = result.buttonAlpha
self.validationLabel.text = result.text
self.validationLabel.textColor = result.textColor
}).disposed(by: disposeBag)
}
//アラート処理
@IBAction func loginButtonTapped(_ sender: Any) {
let alert = UIAlertController(title: "登録しました", message: "\(nameTextField.text!)", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .cancel)
alert.addAction(ok)
self.present(alert, animated: true, completion: nil)
}
}
ViewModel
import RxSwift
import RxCocoa
class ViewModel {
// Validationの結果をenumで表現している
let validationResult: Driver<ValidationResult>
// 3つのTextFieldが空欄かどうかをBool値で表現している
let blankValidation: Driver<Bool>
// パスワードと確認用パスワードが一致しているかをBool値で表現している
let passwordConfirmValidation: Driver<Bool>
init(nameText: Driver<String>, passwordText: Driver<String>, passwordConfirmText: Driver<String>) {
let validationModel = ValidationModel()
blankValidation = Driver.combineLatest(nameText, passwordText, passwordConfirmText) {
name, password, passwordConfirm in
return validationModel.blankValidation(text: [name, password, passwordConfirm])
}
passwordConfirmValidation = Driver.combineLatest(passwordText, passwordConfirmText) {
password, passwordConfirm in
return validationModel.passwordConfirmValidation(password: password, passwordConfirm: passwordConfirm)
}
validationResult = Driver.combineLatest(blankValidation, passwordConfirmValidation) {
blankValidation, passwordConfirmValidation in
if !blankValidation {
return .blankError
} else if !passwordConfirmValidation {
return .passwordConfirmError
}else {
return .ok
}
}
}
}
ValidationModel
import UIKit
enum ValidationResult {
case ok
case blankError
case passwordConfirmError
var isValidated: Bool {
switch self {
case .ok: return true
case .blankError, .passwordConfirmError: return false
}
}
var text: String {
switch self {
case .ok: return "登録可能です"
case .blankError: return "空欄があります"
case .passwordConfirmError: return "パスワードが確認用と一致していません"
}
}
var textColor: UIColor {
switch self {
case .ok: return .green
case .blankError, .passwordConfirmError: return .red
}
}
var buttonAlpha: CGFloat {
switch self {
case .ok: return 1.0
case .blankError, .passwordConfirmError: return 0.4
}
}
}
class ValidationModel {
func blankValidation(text: [String]) -> Bool {
for text in text {
if text.isEmpty {
return false
}
}
return true
}
func passwordConfirmValidation(password: String, passwordConfirm: String) -> Bool {
return password == passwordConfirm
}
}
今回はDriverを使って表現していましたが、まだまだ自分にはDriverやRelay等、理解しきれていない部分が多々あるので、今回のアプリのObservarやRelayを使って同じ挙動を作り、より深く理解していきたいと思います。
以上です!!