[英]RxSwift code runs first time, second time partially
I'm learning RxSwift and i've encountered a problem with login logic. 我正在学习RxSwift,并且遇到登录逻辑问题。
My code runs ok? 我的代码可以运行吗? once, and partially second time, after logout. 登出后一次,部分第二次。
This is from my viewmodel: 这是从我的观点模型:
func transform(input: Input) -> Output {
let user = fetchUser(loginAction: input.loginAction, domain: input.domain,
username: input.username, password: input.password)
return Output(user: user, error: errorTracker.asDriver())
}
func fetchUser(loginAction: Driver<Void>, domain: Driver<String>, email: Driver<String>, password: Driver<String>)->Driver<User>{
let credentials = Driver.combineLatest(domain, email, password) {
$0
}
return loginAction.withLatestFrom(credentials)
.flatMapLatest { [unowned self] (domain, username, password) in
return self.useCase.login(params: ["domain": domain, "username": username, "password": password])
.trackActivity(self.activityIndicator)
.trackError(self.errorTracker)
.asDriverOnErrorJustComplete()
.map { [unowned self] in
if let token = $0.token {
return self.decodeUserId(token: token)
}
return ""
}
.flatMapLatest { [unowned self] userId in
return self.useCase.getUser(params: ["userId": userId])
.trackActivity(self.activityIndicator)
.trackError(self.errorTracker)
.asDriverOnErrorJustComplete()
}
}
}
struct Input {
let loginAction: Driver<Void>
let tenant: Driver<String>
let email: Driver<String>
let password: Driver<String>
}
struct Output {
let user: Driver<User>
let error: Driver<Error>
}
It works first time, login retrieves object which contains a token string, in map part its decoded to get user id, and getUser fetches user by id. 它第一次工作,登录名检索包含令牌字符串的对象,在映射部分将其解码以获取用户ID,而getUser通过ID提取用户。
In view controller i have this binding method: 在视图控制器中,我有这种绑定方法:
func bindViewModel() {
let domainChange = domainField.rx.text.orEmpty.asDriver()
let usernameChange = usernameField.rx.text.orEmpty.asDriver()
let passwordChange = passwordField.rx.text.orEmpty.asDriver()
let input = LoginViewModel.Input(loginAction: loginButton.rx.tap.asDriver(),
domain: domainChange,
username: usernameChange,
password: passwordChange)
let output = viewModel.transform(input: input)
output.user.drive(successBinding).addDisposableTo(disposeBag)
output.error.drive(errorBinding).addDisposableTo(disposeBag)
}
Both successBinding and errorBinding are UIBindingObservers, i think they are not the issue here. successBinding和errorBinding都是UIBindingObservers,我认为这不是这里的问题。 After logout (returning to login, pop) when i try tapping loginButton only the first part runs, login method and retrieves a token successfully, but it doesn't go to mapping logic, or user fetching logic. 注销(返回登录,弹出)后,当我尝试点击loginButton时,只有第一部分运行,登录方法并成功检索了令牌,但它并没有进入映射逻辑或用户获取逻辑。 Any help would be appreciated. 任何帮助,将不胜感激。
I think the culprit is here: 我认为罪魁祸首在这里:
.asDriverOnErrorJustComplete()
.map { [unowned self] in
if let token = $0.token {
return self.decodeUserId(token: token)
}
return ""
}
If the login errors or completes without emitting a next
element, then the token processing in the map will not do anything and nothing will get passed down the chain in that flatMap
. 如果登录错误或在未发出next
元素的情况next
完成登录,则映射中的令牌处理将不执行任何操作,并且该flatMap
的链上不会传递任何东西。
As for cleaning up your code... I would rather see something like this: 至于清理代码……我宁愿看到这样的内容:
func fetchUser(loginAction: Driver<Void>, domain: Driver<String>, email: Driver<String>, password: Driver<String>)->Driver<User>{
let credentials = Driver.combineLatest(domain, email, password)
let latestCredentials = loginAction.withLatestFrom(credentials)
let loginResult = latestCredentials.flatMapLatest { [unowned self] domain, username, password in
self.useCase.login(params: ["domain": domain, "username": username, "password": password])
.trackActivity(self.activityIndicator)
.trackError(self.errorTracker)
.asDriverOnErrorJustComplete()
}
let token = loginResult.map { result in
guard let token = result.token else { return "" }
return token
}
let userID = token.map { [unowned self] in self.decodeUserId(token: $0) }
return userID.flatMapLatest { userID in
return self.useCase.getUser(params: ["userId": userId])
.trackActivity(self.activityIndicator)
.trackError(self.errorTracker)
.asDriverOnErrorJustComplete()
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.