gpt4 book ai didi

ios - RxSwift,将 Action 绑定(bind)到 UIButton 在 View 转换后停止生成事件

转载 作者:行者123 更新时间:2023-11-28 14:29:06 27 4
gpt4 key购买 nike

我正在尝试使用 RxSwift 实现 MVVM 登录屏幕,但遇到了一些困难。

我的登录屏幕(用户、密码、登录按钮)转换为相机 View 屏幕,应用程序会在其中检查相机权限,如果这些权限未获批准,则将用户注销并返回到登录屏幕。

我有一个 loginAction在我的 LoginViewModel返回 Action<Void, LoginResult> , 其中LoginResult Result<Bool, Error> 和我的 loginProvider服务返回 Observable<LoginResult> :

struct LoginViewModel {

let sceneCoordinator: SceneCoordinatorType
let loginProvider: LoginProviderType

var usernameText = Variable<String>("")
var passwordText = Variable<String>("")

var isValid: Observable<Bool> {
return Observable.combineLatest(usernameText.asObservable(), passwordText.asObservable()) { username, password in
username.count > 0 && password.count > 0
}
}

init(loginProvider: LoginProvider, coordinator: SceneCoordinatorType) {
self.loginProvider = loginProvider
self.sceneCoordinator = coordinator
}

lazy var loginAction: Action<Void, LoginResult> = { (coordinator: SceneCoordinatorType, service: LoginProviderType, username: String, password: String) in
return Action<Void, LoginResult>(enabledIf: self.isValid) { _ in
return service.login(username: username, password: password)
.observeOn(MainScheduler.instance)
.do(onNext: { result in
guard let loggedIn = result.value else { return }
if loggedIn {
let cameraViewModel = CameraViewModel(coordinator: coordinator)
coordinator.transition(to: Scene.camera(cameraViewModel), type: .modal)
}
}(self.sceneCoordinator, self.loginProvider, self.companyText.value, self.usernameText.value, self.passwordText.value)
}

一切正常,有效输入成功登录(loginProvider 向我的服务器发送请求,获取响应并相应地处理所有其他步骤)。

如果用户没有授予相机权限,我有一个 Observable为此在我的 CameraViewModel我绑定(bind)到我的 CameraViewController , 订阅并在需要时注销用户并使用 CocoaAction 将 View 弹出回登录屏幕弹出当前 View (使用场景协调器类)。

问题是,当我在转换回登录屏幕后尝试再次登录时,订阅 loginAction 发出的元素不接收任何元素。

这是 LoginViewController 的代码:

class LoginViewController: UIViewController, BindableType {

var viewModel: LoginViewModel!

private let disposeBag = DisposeBag()

private var loginAction: Action<Void, LoginResult>!

@IBOutlet weak var usernameTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var loginButton: UIButton!
@IBOutlet weak var loadingIndicator: UIActivityIndicatorView!


private var usernameObservable: Observable<String> {
return usernameTextField.rx.text
.throttle(0.5, scheduler: MainScheduler.instance)
.map() { text in
return text ?? ""
}
}

private var passwordObservable: Observable<String> {
return passwordTextField.rx.text
.throttle(0.5, scheduler: MainScheduler.instance)
.map() { text in
return text ?? ""
}
}

override func viewDidLoad() {
super.viewDidLoad()

}

func bindViewModel() {

usernameObservable
.bind(to: viewModel.usernameText)
.disposed(by: disposeBag)

passwordObservable
.debug()
.bind(to: viewModel.passwordText)
.disposed(by: disposeBag)

loginAction = viewModel.loginAction

loginAction.elements
.subscribe(onNext: { [weak self] result in
self?.loadingIndicator.stopAnimating()
var message = ""
switch result {
case .failure(.unknownError):
message = "unknown error"
case .failure(.wrongCredentials):
message = "wrong credentials"
case .failure(.serviceUnavailable):
message = "service unavailable"
case let .success(loggedIn):
return
}
self?.errorMessage(message: message)
}).disposed(by: disposeBag)

loginButton.rx.tap
.subscribe(onNext: { [unowned self] in
self.loadingIndicator.startAnimating()
self.loginAction.execute(Void())
})
.disposed(by: disposeBag)

viewModel.isValid
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
}

我可以看到点击登录按钮会产生点击事件,但是 Action 本身会停止调用。知道我错过了什么吗?

最佳答案

我不确定 ScreenCoordinator 是如何工作的,但我会从将 usernameObservable/passwordObservable 的创建移至 viewDidLoad() 开始,因为这个问题似乎与生命周期相关。此外,您可以添加更多的 .debug() 调用(带有参数以便能够在日志中区分它们)。

关于ios - RxSwift,将 Action 绑定(bind)到 UIButton 在 View 转换后停止生成事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51363282/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com