Swift 仅在rx_抽头事件时调用方法
我对rxswift有一个基本问题。 我有一个登录屏幕,当且仅当我点击登录按钮时,它应该在视图模型内调用我的登录方法Swift 仅在rx_抽头事件时调用方法,swift,rx-swift,Swift,Rx Swift,我对rxswift有一个基本问题。 我有一个登录屏幕,当且仅当我点击登录按钮时,它应该在视图模型内调用我的登录方法 loginButton.rx_tap .doOn({[unowned self] _ in self.loginButton.enabled = false }) .flatMap({[unowned self] in self.loginModel.login() }) .su
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 { ($0.rangeOfString("@") != nil) || ($0.utf8.count == 0) }
}
}
var pwdValid : Driver<Bool> {
get {
return passwordDriver
.throttle(0.5)
.filterEmpty()
.distinctUntilChanged()
.map { ($0.utf8.count > 5) || ($0.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)
}
}
var凭证:驱动程序{
返回Driver.combineTest(userNameDriver.distinctUntilChanged(),passwordDriver.distinctUntilChanged()){usr,pwd in
返回(usr、pwd)
}
}
var usrValid:驱动程序{
得到{
返回用户名驱动程序
.节气门(0.5)
.filterrempty()
.distinctUntilChanged()
.map{($0.rangeOfString(“@”)!=nil)| |($0.utf8.count==0)}
}
}
var pwdValid:驱动程序{
得到{
返回密码驱动程序
.节气门(0.5)
.filterrempty()
.distinctUntilChanged()
.map{($0.utf8.count>5)| |($0.utf8.count==0)}
}
}
var usernameBorderColor:可观察!
var passwordBorderColor:可观察!
var credentialValid:驱动程序{
返回驱动程序。组合测试(usrValid,pwdValid){usr,pwd-in
返回(usr和pwd)
}
}
有人能帮我吗?
谢谢我审阅了你的项目。问题在于ViewModel的体系结构不是很好。我使用来自的示例修复了一个。请参见下面的新视图模型:
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) { ($0, $1) }
validatedUsername = input.userName.map { $0.rangeOfString("@") != nil }
validatedPassword = input.password.map { $0.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)
}
}
我创建了pull请求,您必须接受它并查看完整的源代码。祝你好运 嘿!我无法复制这个bug,因为它对我来说并不明显。您可以通过登录Github创建简单的项目吗?我将克隆它,帮助您修复它,并在本主题中编写解决方案。在这里,您可以找到该项目:我添加了一个示例,只是为了查看问题。如果您在文本字段中输入user并通过,然后点击login,您将得到一个基于结果的回复…例如,您写入了错误的凭据并点击login,您将在SubscribeText中获得结果,但是,如果你尝试写入新凭据,信号会再次启动…我只想取消以前的信号,并在点击按钮登录时启动新信号。非常感谢,我刚刚合并,今晚我查看了你的代码:)@Svyatoslav这真的帮了我大忙。谢谢你如此详尽的回答。@Danny谢谢。很乐意帮忙。
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)