问题描述
我需要使用单选按钮验证表单,但是我不能共享我的代码:
我的观点:
private func registerForm() {
tvUserName.rx.text.map { $0 ?? "" }.bind(to: viewmodel.userNamePublishSubject).disposed(by: disposeBag)
tvEmail.rx.text.map { $0 ?? "" }.bind(to: viewmodel.emailPublishSubject).disposed(by: disposeBag)
tvPassword.rx.text.map { $0 ?? "" }.bind(to: viewmodel.passwordPublishSubject).disposed(by: disposeBag)
tvRepeatPassword.rx.text.map { $0 ?? "" }.bind(to: viewmodel.repeatPasswordPublishSubject).disposed(by: disposeBag)
viewmodel.formLoginNativaIsValid().bind(to: btnNext.rx.isEnabled).disposed(by: disposeBag)
checkBoxOutlet.rx.tap
.scan(false) { lastValue,_ in
return !lastValue
}
.bind(to: btnNext.rx.isEnabled)
.disposed(by: disposeBag)
}
我的viewmodel:
let userNamePublishSubject = PublishSubject<String>()
let emailPublishSubject = PublishSubject<String>()
let passwordPublishSubject = PublishSubject<String>()
let repeatPasswordPublishSubject = PublishSubject<String>()
func formLoginNativaIsValid() -> Observable<Bool> {
return Observable.combineLatest(userNamePublishSubject.asObserver(),emailPublishSubject.asObserver(),passwordPublishSubject.asObserver(),repeatPasswordPublishSubject.asObserver()).map { userName,email,password,repeatPassword in
return self.validateRegister(userName: userName,email: email,password: password,repeatPassword: repeatPassword)
}.startWith(false)
}
private func validateRegister(userName: String,email: String,password: String,repeatPassword: String) -> Bool {
return userName.count >= 5 && email.isEmail() && password.count >= 5 && repeatPassword.count >= 5 && password == repeatPassword
}
我已经验证了表单,但是我还需要用户接受启用“下一步”按钮的条款和条件。
解决方法
在设计反应系统时,您需要考虑因果关系。每个可观察到的链应该集中在一个单一的影响上,并根据需要引入尽可能多的原因。就像一个函数传入多个参数并返回一个值一样。
在这种情况下,您的效果是btnNext.rx.isEnabled
。您必须考虑什么因素导致这种影响发生变化?这是我的写法示例:
class View: UIView {
weak var tvUserName: UITextView!
weak var tvEmail: UITextView!
weak var tvPassword: UITextView!
weak var tvRepeatPassword: UITextView!
weak var btnNext: UIButton!
weak var checkBoxOutlet: UIButton!
let disposeBag = DisposeBag()
override func awakeFromNib() {
super.awakeFromNib()
isNextButtonEnabled(
username: tvUserName.rx.text.orEmpty.asObservable(),email: tvEmail.rx.text.orEmpty.asObservable(),password: tvPassword.rx.text.orEmpty.asObservable(),repeatPassword: tvRepeatPassword.rx.text.orEmpty.asObservable(),checkBox: checkBoxOutlet.rx.tap.asObservable()
)
.bind(to: btnNext.rx.isEnabled)
.disposed(by: disposeBag)
}
}
func isNextButtonEnabled(username: Observable<String>,email: Observable<String>,password: Observable<String>,repeatPassword: Observable<String>,checkBox: Observable<Void>) -> Observable<Bool> {
return Observable.combineLatest(
[
username.map { $0.count >= 5 },email.map { $0.isEmail() },password.map { $0.count >= 5 },Observable.combineLatest(password,repeatPassword) { $0 == $1 },checkBox.scan(false) { state,_ in !state }.startWith(false)
]
)
.map { $0.allSatisfy { $0 } }
}
请注意,这里的视图模型有多简单。这是isNextButtonEnabled
函数。它可以很容易地进行测试,但是它是如此简单,以至于您甚至可能都不觉得需要进行测试。所有确定下一个按钮是否启用的条件都集中在一个地方,以便于理解。不需要一堆PublishSubjects。它更容易阅读和理解。