我在公司经常看到的一件事是 Rx 的使用,Variable
类似于. 这默认为 false,当运行命令登录时,我们将其翻转为 true。该布尔值也与登录按钮相关联,因此一旦用户单击登录,任何后续单击都不会执行任何操作。您可以在用户单击某些内容以更改屏幕以确保没有正在进行的呼叫/事件的任何地方实现此功能。loginInFlight
Variable<boolean>
我们遵循 MVVM,所以这里有一个基于此的示例。我试图只显示它下面的准系统,所以希望下面的一切仍然有意义。
登录视图控制器
class LoginViewController: UIViewController {
@IBOutlet weak var signInButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
...
// This commandAvailable is what I was talking about above
viewModel?
.loginCommandAvailable
.subscribe(onNext: {[unowned self] (available: Bool) in
self.signInButton.isEnabled = available
})
.addDisposableTo(disposeBag)
signInButton.rx.tap
.map {
// Send Login Command
return viewModel?.loginCommand()
}.subscribe(onNext: { (result: LoginResult)
// If result was successful we can send the user to the next screen
}).addDisposableTo(disposeBag)
}
}
登录视图模型
enum LoginResult: Error {
case success
case failure
}
class LoginViewModel {
private let loginInFlight = Variable<Bool>(false)
private var emailAddressProperty = Variable<String>("")
var emailAddress: Driver<String> {
return emailAddressProperty
.asObservable()
.subscribeOn(ConcurrentDispatchQueueScheduler(queue: DispatchQueue.global()))
.asDriver(onErrorJustReturn: "")
}
...
var loginCommandAvailable: Observable<Bool> {
// We let the user login if login is not currently happening AND the user entered their email address
return Observable.combineLatest(emailAddressProperty.asObservable(), passwordProperty.asObservable(), loginInFlight.asObservable()) {
(emailAddress: String, password: String, loginInFlight: Bool) in
return !emailAddress.isEmpty && !password.isEmpty && !loginInFlight
}
}
func loginCommand() -> Driver<LoginResult> {
loginInFlight.value = true
// Make call to login
return authenticationService.login(email: emailAddressProperty.value, password: passwordProperty.value)
.map { result -> LoginResult in
loginInFlight.value = false
return LoginResult.success
}
}
}
根据可用性编辑切换命令
登录视图控制器
class LoginViewController: UIViewController {
@IBOutlet weak var signInButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
...
// This commandAvailable is what I was talking about above
viewModel?
.loginCommandAvailable
.subscribe(onNext: {[unowned self] (available: Bool) in
self.signInButton.isEnabled = available
})
.addDisposableTo(disposeBag)
signInButton.rx.tap
.map {
return viewModel?.loginCommandAvailable
}.flatmap { (available: Bool) -> Observable<LoginResult>
// Send Login Command if available
if (available) {
return viewModel?.loginCommand()
}
}.subscribe(onNext: { (result: LoginResult)
// If result was successful we can send the user to the next screen
}).addDisposableTo(disposeBag)
}
}