我想在点击按钮时检查文本是否有效。如果验证失败,它将在UILabel上显示错误文本,并且不发送请求。否则,如果验证成功,它将发送请求。
我看到了很多有关登录的演示,但是它们控制了按钮的启用,以避免在点击按钮时验证数据。我对此感到困惑。
我已经写了一些代码。
class LoginViewModel: BaseViewModel, ViewModelType {
struct Input {
let loginTaps: Driver<Void>
}
struct Output {
let validatedUsername: Driver<Bool>
let validatedPassword: Driver<Bool>
}
let username = BehaviorRelay(value: "")
let password = BehaviorRelay(value: "")
let loginTapped = PublishSubject<Void>()
func transform(input: Input) -> Output {
let validatedUsername = username.asDriver(onErrorJustReturn: "").map { username in
return username.isPhoneNumber
}
let validatedPassword = password.asDriver(onErrorJustReturn: "").map { password in
return password.count > 7
}
input.loginTaps.map { () -> Void in
<#code#>
// I want do check and then do network request
}
input.loginTaps.drive(onNext: { [weak self] () in
self?.loginTapped.onNext(())
}).disposed(by: rx.disposeBag)
loginTapped.flatMapLatest { _ -> Observable<RxSwift.Event<Token>> in
// and if I want to return Bool not Token, how should I do????????????
return self.provider.login(username: self.username.value, password: self.password.value)
.asObservable()
.materialize()
}.subscribe(onNext: { (event) in
switch event {
case .next(let token):
AuthManager.setToken(token: token)
case .error(let error):
log.error(error.localizedDescription)
default: break
}
}).disposed(by: rx.disposeBag)
return Output(validatedUsername: validatedUsername,
validatedPassword: validatedPassword)
}
}
答案 0 :(得分:0)
我希望看到这样的东西:
class LoginViewModel {
struct Input {
let loginTap: Signal<Void>
let username: Driver<String>
let password: Driver<String>
}
struct Output {
let errorText: Driver<String>
let loginSuccess: Signal<Void>
}
var networkRequest: (URLRequest) -> Observable<Data> = { _ in fatalError("need to replace this with an implementation.") }
func transform(input: Input) -> Output {
func isValidCredentials(username: String, password: String) -> Bool {
return username.isPhoneNumber && password.count > 7
}
let credentials = Driver.combineLatest(input.username, input.password)
// this chain emits when the login button is tapped and the credentials are invalid
let invalidInputError = input.loginTap
.withLatestFrom(credentials)
.filter { !isValidCredentials(username: $0, password: $1) }
.map { _ in "Credentials are invalid" }
.asDriver(onErrorRecover: { _ in fatalError("can't get here") })
let networkRequest = self.networkRequest // to avoid dealing with `self` in the flatMap below
// this chain makes a request if the login button is tapped while the credentials are valid
let loginResult = input.loginTap
.withLatestFrom(credentials)
.filter { isValidCredentials(username: $0, password: $1) }
.map { URLRequest.login(username: $0, password: $1) }
.asObservable()
.flatMapLatest { networkRequest($0).materialize() }
.share(replay: 1)
// this chain emits when the login result produces an error
let loginError = loginResult
.map { $0.error }
.filter { $0 != nil }
.map { $0!.localizedDescription }
.asDriver(onErrorRecover: { _ in fatalError("can't get here") })
// this chain emits when the login result succeeds
let loginSuccess = loginResult
.filter { $0.element != nil }
.map { _ in }
.asSignal(onErrorRecover: { _ in fatalError("can't get here") })
let errorText = Driver.merge(invalidInputError, loginError)
return Output(errorText: errorText, loginSuccess: loginSuccess)
}
}