繁体   English   中英

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

[英]How to implement firebase auth into MVVM-C RxSwift

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

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

我的虚拟机代码:

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, Storyboarded {

    @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)

    }
}

我把我的视图模型作为一个函数,很大程度上取决于你想对结果做什么,但这里有一些示例代码可能对你有帮助:

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM