Я делаю мои модели представления как функцию, и многое зависит от того, что именно вы хотите сделать с результатом, но вот пример кода, который может вам помочь:
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)