MVVMSample

# はじめに
RxSwift勉強中です。
今回は


https://www.yukendev.com/blogs/swift-mvvm

を参考に、MVVMについて勉強したので、アウトプットしていきたいと思います。
とても解りやすくまとめられていて、すごく勉強になりました😁
ありがとうございました!!
今回は、よくあるログイン画面を作成しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/1d598ceb-d4c1-9cb0-8279-6269d24e5014.png" width=40%>
コード全文

```swift: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)
    }
}
```

```swift: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
            }
        }
    }
}
```
```swift: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を使って同じ挙動を作り、より深く理解していきたいと思います。

以上です!!