如何在MVVM-C RxSwift中实现Firebase身份验证

问题描述 投票:2回答:1

我正在尝试实现MVVM-C rx swift应用程序。

我有一个用于注册视图控制器的虚拟机,并将用户名和密码作为行为主题。我还将一个Firebase处理程序注入了VM。将注册结果传递回VC的最佳方法是什么。

我的VM代码:

class CreateVM {

let firebase: FirebaseHandler
let email: String

var password = BehaviorSubject<String>(value: "")
var confirmPassword = BehaviorSubject<String>(value: "")

var shouldHideButton: Observable<Bool> {
    return Observable.combineLatest(password.asObservable(), confirmPassword.asObservable()) { pass, confPass in
        !(pass.count >= 5 && pass == confPass)
    }
}

init(firebase: FirebaseHandler, email: String) {
    self.firebase = firebase
    self.email = email
}

func submit() {
    let pass = try! password.value()
    firebase.createWithEmail(email: email, password: pass) { (result) in
        switch result {
        case .success(let uid):
            print(uid, "created")
            //handle successful creation
        case .failure(let err):
            print("failed with error:", err)
            //handler error
        }
    }
}

}

我的VC代码:

Class CreateVC:UIViewController,故事板{

@IBOutlet weak var createButton: Rounded!
@IBOutlet weak var passwordEntry: UITextField!
@IBOutlet weak var confirmPasswordEntry: UITextField!

weak var coordinator: AuthCoordinator?

var displayName: String!
var viewModel: CreateVM!
let disposeBag = DisposeBag()

override func viewDidLoad() {
    super.viewDidLoad()

    bindUI()
}

func bindUI() {
    passwordEntry.rx.text.orEmpty.bind(to: viewModel.password).disposed(by: disposeBag)
    confirmPasswordEntry.rx.text.orEmpty.bind(to: viewModel.confirmPassword).disposed(by: disposeBag)
    viewModel.shouldHideButton.bind(to: createButton.rx.isHidden).disposed(by: disposeBag)

    createButton.rx.tap.bind { [unowned self] _ in
            self.viewModel.submit()
    }.disposed(by: disposeBag)

}

}

ios swift mvvm firebase-authentication rx-swift
1个回答
0
投票

我将视图模型作为函数来使用,并且很大程度上取决于您要对结果执行什么操作,但是这里有一些示例代码可能会对您有所帮助:

struct CreateInput {
    let password: Observable<String>
    let confirm: Observable<String>
    let submit: Observable<Void>
}

struct CreateOutput {
    let displayName: String
    let shouldHideButton: Observable<Bool>
    let signUpResult: Observable<Result<Int, Error>>
}

func createVM(firebase: FirebaseHandler, email: String) -> (CreateInput) -> CreateOutput {
    return { input in
        let shouldHideButton = Observable.combineLatest(input.password, input.confirm) { $0.count < 5 || $0 != $1 }
        let credentials = Observable.combineLatest(Observable.just(email), input.password) { (email: $0, password: $1) }
        let signUpResult = input.submit
            .withLatestFrom(credentials)
            .flatMapLatest {
                firebase.create(email: $0.email, password: $0.password)
        }

        return CreateOutput(
            displayName: email,
            shouldHideButton: shouldHideButton,
            signUpResult: signUpResult
        )
    }
}

extension FirebaseHandler {
    func create(email: String, password: String) -> Observable<Result<Int, Error>> {
        Observable.create { observer in
            self.createWithEmail(email: email, password: password) { (result) in
                observer.onNext(result)
                observer.onCompleted()
            }
            return Disposables.create()
        }
    }
}

final class CreateViewController: UIViewController {

    @IBOutlet weak var displayNameLabel: UILabel!
    @IBOutlet weak var createButton: UIButton!
    @IBOutlet weak var passwordEntry: UITextField!
    @IBOutlet weak var confirmPasswordEntry: UITextField!

    var bindUI: (CreateInput) -> CreateOutput = { _ in fatalError() } // assign `createVM(firebase: myFirebaseHandler, email: "myEmail")` to this before it loads.
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        let input = CreateInput(
            password: passwordEntry.rx.text.orEmpty.asObservable(),
            confirm: confirmPasswordEntry.rx.text.orEmpty.asObservable(),
            submit: createButton.rx.tap.asObservable()
        )
        let output = bindUI(input)

        displayNameLabel.text = output.displayName

        output.shouldHideButton
            .bind(to: createButton.rx.isHidden)
            .disposed(by: disposeBag)

        output.signUpResult
            .bind { result in
                switch result {
                case .success(let uid):
                    print("uid:", uid)
                case .failure(let error):
                    print("error:", error.localizedDescription)
                }
            }
            .disposed(by: disposeBag)
    }
}

如果高阶函数使您感到紧张,则可以将其包装为一种类型:

struct CreateVM {

    struct Input {
        let password: Observable<String>
        let confirm: Observable<String>
        let submit: Observable<Void>
    }

    struct Output {
        let displayName: String
        let shouldHideButton: Observable<Bool>
        let signUpResult: Observable<Result<Int, Error>>
    }

    let firebase: FirebaseHandler
    let email: String

    func bind(_ input: Input) -> Output {
        let shouldHideButton = Observable.combineLatest(input.password, input.confirm) { $0.count < 5 || $0 != $1 }
        let credentials = Observable.combineLatest(Observable.just(email), input.password) { (email: $0, password: $1) }
        let signUpResult = input.submit
            .withLatestFrom(credentials)
            .flatMapLatest { [unowned firebase] in
                firebase.create(email: $0.email, password: $0.password)
            }

        return Output(
            displayName: email,
            shouldHideButton: shouldHideButton,
            signUpResult: signUpResult
        )
    }
}

然后您的视图控制器将具有一个属性:var viewModel: CreateVM!并使用以下命令构建输出:let output = viewModel.bind(input)

© www.soinside.com 2019 - 2024. All rights reserved.