[英]Binding UITextField or button with viewModel
I have been facing an issue with binding UITextField or button with observables in viewModel. 我一直在将UITextField或按钮与viewModel中的可观察对象绑定时遇到问题。
class VM {
var emailObservable: Observable<String?> = Observable.just("")
}
I have this observable for email in my viewModel and in controller. 我在viewModel和控制器中都有可观察到的电子邮件。 When i try to bind my textfield with it, it gives me error
当我尝试用它绑定文本框时,它给我错误
Cannot invoke 'bind' with an argument list of type '(to: Observable)'.
无法使用类型为((to:Observable)'的参数列表调用'bind'。
But when i replace the observables with Variable, it works fine. 但是,当我用变量替换可观察对象时,它可以正常工作。
Can someone please help me with this. 有人可以帮我吗 I found answers which mainly include passing the observable in the init method of viewModel, but i don't want to pass it in the init method.
我找到了答案,主要包括在viewModel的init方法中传递observable,但我不想在init方法中传递它。
This is the link i found for binding but it is through init method. 这是我发现用于绑定的链接,但这是通过init方法进行的。
How to bind rx_tap (UIButton) to ViewModel? 如何将rx_tap(UIButton)绑定到ViewModel?
I think here what you looking for: 我认为您在这里寻找什么:
final class ViewModel {
private let bag = DisposeBag()
let string = BehaviorSubject<String>(value: "")
init() {
string.asObservable().subscribe(onNext: { string in
print(string)
})
.disposed(by: bag)
}
}
final class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
private let bag = DisposeBag()
private var viewModel: ViewModel!
override func viewDidLoad() {
super.viewDidLoad()
viewModel = ViewModel()
textField.rx.text
.orEmpty
.bind(to: viewModel.string)
.disposed(by: bag)
}
}
Note, as @MaximVolgin mentioned Variable
is deprecated in RxSwift 4 , so you can use BehaviorSubject
or other that's up to you. 注意,由于@MaximVolgin提到的
Variable
在RxSwift 4中已弃用 ,因此您可以使用BehaviorSubject
或其他取决于您的行为。
UPD. UPD。
Implementation with Observable
only. 仅
Observable
实现。
final class ViewModel {
private let bag = DisposeBag()
var string = "" {
didSet {
print(string)
}
}
init(stringObservable: Observable<String>) {
stringObservable.subscribe(onNext: { string in
self.string = string
})
.disposed(by: bag)
}
}
final class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
private let bag = DisposeBag()
private var viewModel: ViewModel!
override func viewDidLoad() {
super.viewDidLoad()
viewModel = ViewModel(stringObservable: textField.rx.text.orEmpty.asObservable())
}
}
As you can see, your solution can be implemented using Observable
, not Variable
or any kind of Subject
. 如您所见,可以使用
Observable
而不是Variable
或任何Subject
来实现您的解决方案。 Also should be mentioned that in most cases this is not the final logic (just bind textField or whatever to some variable). 还应该提到的是,在大多数情况下,这不是最终的逻辑(只需将textField或其他内容绑定到某个变量)。 There can be some validation, enable/disable, etc. logic.
可能会有一些验证,启用/禁用等逻辑。 For this cases RxSwift provide
Driver
. 对于这种情况,RxSwift提供了
Driver
。 Also nice example about differences in using Observable
and Driver
for one project can be found here (by RxSwift). 在此处 (通过RxSwift)也可以找到关于在一个项目中使用
Observable
和Driver
区别的一个很好的示例。
Method .bind(to:) binds to an Observer , not Observable . 方法.bind(to :)绑定到Observer ,而不是Observable 。
Variable (deprecated in RxSwift v4) is a special-purpose Subject . 变量 (在RxSwift v4中已弃用)是一个特殊用途的Subject 。
Subject s are by definition both Observer and Observable . 根据定义, 主题是Observer和Observable 。
This is what .bind(to:) does inside - 这是.bind(to :)在内部执行的操作-
public func bind<O: ObserverType>(to observer: O) -> Disposable where O.E == E {
return self.subscribe(observer)
}
UPDATE: 更新:
How to avoid passing observables in .init() of VM: 如何避免在VM的.init()中传递可观察对象:
// inside VM:
fileprivate let observableSwitch: BehaviorSubject<Observable<MyValue>>
fileprivate let myValueObservable = observableSwitch.switchLatest()
// instead of passing in init:
public func switch(to observable: Observable<MyValue>) {
self.observableSwitch.onNext(observable)
}
Take a subject of variable type in ViewModel class: 在ViewModel类中获取一个变量类型的主题:
class ViewModel{
//MARK: - local Variables
var emailText = Variable<String?>("")
}
Now create object of viewmodel class in viewController class and bind this emailtext variable to textfield in viewcontroller.Whenever textfield text will change then it emailText of viewmodel gets value. 现在在viewController类中创建viewmodel类的对象,并将此emailtext变量绑定到viewcontroller中的textfield。每当文本字段文本发生变化时,viewmodel的emailText就会获得价值。
txtfield.rx.text
.bindTo(viewModel.emailText).addDisposableTo(disposeBag)
Instead of 代替
emailTextfield.rx.text.asObservable().bind(to: viewModel.emailObservable).disposed(by: disposeBag)
use this code 使用此代码
viewModel.emailObservable.bind(to: noteField.rx.text).disposed(by: disposeBag)
Probably, you want to make two way binding , so read more about it here 可能您想进行双向绑定 ,因此请在此处详细了解
Try this, 尝试这个,
override func viewDidLoad() {
super.viewDidLoad()
_ = userNameTextField.rx.text.map { $0 ?? "" }.bind(to: viewModel.userName)
}
in viewModel class, 在viewModel类中,
class ViewModel{
var userName: Variable<String> = Variable("")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.