我正在尝试实现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)
}
}
我将视图模型作为函数来使用,并且很大程度上取决于您要对结果执行什么操作,但是这里有一些示例代码可能会对您有所帮助:
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)