仅在 rx_tap 事件上调用方法
call method only on rx_tap event
我有一个关于 rxswift 的基本问题。
我有一个登录屏幕,当且仅当我点击登录按钮时,它应该在视图模型中调用我的登录方法
loginButton.rx_tap
.doOn({[unowned self] _ in
self.loginButton.enabled = false
})
.flatMap({[unowned self] in self.loginModel.login() })
.subscribeNext({ [weak self] login in
self?.loginButton.enabled = true
guard login?.result == 1 else {
self?.showErrorWithMessage(login!.message)
return;
}
// Logged in!
})
.addDisposableTo(disposeBag)
看起来不错,但如果由于凭据无效而导致登录失败并且用户重新开始在文本字段中键入,则会再次触发对 loginModel.login() 的调用...
在视图模型中还有:
var credentials : Driver<(String, String)> {
return Driver.combineLatest(userNameDriver.distinctUntilChanged(), passwordDriver.distinctUntilChanged()) { usr, pwd in
return (usr, pwd)
}
}
var usrValid : Driver<Bool> {
get {
return userNameDriver
.throttle(0.5)
.filterEmpty()
.distinctUntilChanged()
.map { ([=12=].rangeOfString("@") != nil) || ([=12=].utf8.count == 0) }
}
}
var pwdValid : Driver<Bool> {
get {
return passwordDriver
.throttle(0.5)
.filterEmpty()
.distinctUntilChanged()
.map { ([=12=].utf8.count > 5) || ([=12=].utf8.count == 0) }
}
}
var usernameBorderColor : Observable<UIColor>!
var passwordBorderColor : Observable<UIColor>!
var credentialValid : Driver<Bool> {
return Driver.combineLatest(usrValid, pwdValid) { usr, pwd in
return (usr && pwd)
}
}
有人可以帮我解决这个问题吗?
谢谢
我审查了你的项目。问题不是您的 ViewModel 的架构很好。我使用 RxSwift repo 中的示例修复了一个。在下面查看您的新视图模型:
class LoginViewModel
{
let validatedUsername: Driver<Bool>
let validatedPassword: Driver<Bool>
// Is login button enabled
let loginEnabled: Observable<Bool>
// Has user log in
let loggedIn: Observable<Login>
var usernameBorderColor : Observable<UIColor>
var passwordBorderColor : Observable<UIColor>
init(input: (
userName: Driver<String>,
password: Driver<String>,
loginClick: Observable<Void>
),
dependency: (
RxMoyaProvider<APIProvider>
)
) {
let credentials = Driver.combineLatest(input.userName, input.password) { ([=10=], ) }
validatedUsername = input.userName.map { [=10=].rangeOfString("@") != nil }
validatedPassword = input.password.map { [=10=].utf8.count > 5 }
usernameBorderColor = validatedUsername.asObservable()
.map{valid in
return valid ? UIColor.clearColor() : UIColor.redColor()
}
passwordBorderColor = validatedPassword.asObservable()
.map{valid in
return valid ? UIColor.clearColor() : UIColor.redColor()
}
loginEnabled = Observable.combineLatest(
validatedUsername.asObservable(),
validatedPassword.asObservable()
) { username, password in
username &&
password
}
.distinctUntilChanged()
.shareReplay(1)
loggedIn = input.loginClick.withLatestFrom(credentials)
.flatMap { username, password -> Observable<Login> in
var resultLogin : Login
if username == "test@" && password == "123123" {
resultLogin = Login(result: 1, message: "OK")
}
else {
resultLogin = Login(result: 0, message: "KO")
}
return Observable.create { observer in
observer.onNext(resultLogin)
observer.onCompleted()
return AnonymousDisposable {
}
}
}
.retry()
.shareReplay(1)
}
}
您还必须更改登录视图控制器:
let viewModel = LoginViewModel(
input: (
userName: userTextField.rx_text.asDriver(),
password: pwdTextField.rx_text.asDriver(),
loginClick: loginButton.rx_tap.asObservable()
),
dependency: (
apiProvider
)
)
viewModel.loginEnabled
.subscribeNext { [weak self] valid in
self?.loginButton.enabled = valid
self?.loginButton.alpha = valid ? 1.0 : 0.5
}
.addDisposableTo(self.disposeBag)
viewModel.loggedIn
.subscribeNext { login in
print(login.message)
guard login.result == 1 else {
// Show error
return;
}
}
.addDisposableTo(disposeBag)
我创建了拉取请求,您必须接受它并查看完整的源代码。祝你好运!
我有一个关于 rxswift 的基本问题。 我有一个登录屏幕,当且仅当我点击登录按钮时,它应该在视图模型中调用我的登录方法
loginButton.rx_tap
.doOn({[unowned self] _ in
self.loginButton.enabled = false
})
.flatMap({[unowned self] in self.loginModel.login() })
.subscribeNext({ [weak self] login in
self?.loginButton.enabled = true
guard login?.result == 1 else {
self?.showErrorWithMessage(login!.message)
return;
}
// Logged in!
})
.addDisposableTo(disposeBag)
看起来不错,但如果由于凭据无效而导致登录失败并且用户重新开始在文本字段中键入,则会再次触发对 loginModel.login() 的调用...
在视图模型中还有:
var credentials : Driver<(String, String)> {
return Driver.combineLatest(userNameDriver.distinctUntilChanged(), passwordDriver.distinctUntilChanged()) { usr, pwd in
return (usr, pwd)
}
}
var usrValid : Driver<Bool> {
get {
return userNameDriver
.throttle(0.5)
.filterEmpty()
.distinctUntilChanged()
.map { ([=12=].rangeOfString("@") != nil) || ([=12=].utf8.count == 0) }
}
}
var pwdValid : Driver<Bool> {
get {
return passwordDriver
.throttle(0.5)
.filterEmpty()
.distinctUntilChanged()
.map { ([=12=].utf8.count > 5) || ([=12=].utf8.count == 0) }
}
}
var usernameBorderColor : Observable<UIColor>!
var passwordBorderColor : Observable<UIColor>!
var credentialValid : Driver<Bool> {
return Driver.combineLatest(usrValid, pwdValid) { usr, pwd in
return (usr && pwd)
}
}
有人可以帮我解决这个问题吗? 谢谢
我审查了你的项目。问题不是您的 ViewModel 的架构很好。我使用 RxSwift repo 中的示例修复了一个。在下面查看您的新视图模型:
class LoginViewModel
{
let validatedUsername: Driver<Bool>
let validatedPassword: Driver<Bool>
// Is login button enabled
let loginEnabled: Observable<Bool>
// Has user log in
let loggedIn: Observable<Login>
var usernameBorderColor : Observable<UIColor>
var passwordBorderColor : Observable<UIColor>
init(input: (
userName: Driver<String>,
password: Driver<String>,
loginClick: Observable<Void>
),
dependency: (
RxMoyaProvider<APIProvider>
)
) {
let credentials = Driver.combineLatest(input.userName, input.password) { ([=10=], ) }
validatedUsername = input.userName.map { [=10=].rangeOfString("@") != nil }
validatedPassword = input.password.map { [=10=].utf8.count > 5 }
usernameBorderColor = validatedUsername.asObservable()
.map{valid in
return valid ? UIColor.clearColor() : UIColor.redColor()
}
passwordBorderColor = validatedPassword.asObservable()
.map{valid in
return valid ? UIColor.clearColor() : UIColor.redColor()
}
loginEnabled = Observable.combineLatest(
validatedUsername.asObservable(),
validatedPassword.asObservable()
) { username, password in
username &&
password
}
.distinctUntilChanged()
.shareReplay(1)
loggedIn = input.loginClick.withLatestFrom(credentials)
.flatMap { username, password -> Observable<Login> in
var resultLogin : Login
if username == "test@" && password == "123123" {
resultLogin = Login(result: 1, message: "OK")
}
else {
resultLogin = Login(result: 0, message: "KO")
}
return Observable.create { observer in
observer.onNext(resultLogin)
observer.onCompleted()
return AnonymousDisposable {
}
}
}
.retry()
.shareReplay(1)
}
}
您还必须更改登录视图控制器:
let viewModel = LoginViewModel(
input: (
userName: userTextField.rx_text.asDriver(),
password: pwdTextField.rx_text.asDriver(),
loginClick: loginButton.rx_tap.asObservable()
),
dependency: (
apiProvider
)
)
viewModel.loginEnabled
.subscribeNext { [weak self] valid in
self?.loginButton.enabled = valid
self?.loginButton.alpha = valid ? 1.0 : 0.5
}
.addDisposableTo(self.disposeBag)
viewModel.loggedIn
.subscribeNext { login in
print(login.message)
guard login.result == 1 else {
// Show error
return;
}
}
.addDisposableTo(disposeBag)
我创建了拉取请求,您必须接受它并查看完整的源代码。祝你好运!