如何在 MVVM-C RxSwift 中实现 firebase 身份验证
Posted
技术标签:
【中文标题】如何在 MVVM-C RxSwift 中实现 firebase 身份验证【英文标题】:How to implement firebase auth into MVVM-C RxSwift 【发布时间】:2020-03-25 12:27:07 【问题描述】:我正在尝试实现一个 MVVM-C rx swift 应用程序。
我的注册视图控制器有一个虚拟机,用户名和密码作为行为主体。我还有一个注入 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)
【问题讨论】:
VC想对注册结果做什么? 【参考方案1】:我将我的视图模型作为一个函数来做,很大程度上取决于你想对结果做什么,但这里有一些示例代码可能会对你有所帮助:
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)
【讨论】:
感谢这极大地帮助了我理解 VM 和 VC 应该如何通信。它也给了我一些关于我需要复习的事情的指示,但总的来说我确实理解你的实现:D 非常感谢!以上是关于如何在 MVVM-C RxSwift 中实现 firebase 身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用 Observable 绑定 BehaviorRelay - RxSwift
在 RxSwift 中设置 TextField 字符的限制 [重复]