RxSwft is very suitable for iOS MVVM.
Putting viewmodel everywhere, disobeys Law of Demeter ( The Least Knowledge Principle ).
What is the other drawbacks?
Will it leads to Memory Leakage?
Here is an example:
ViewController has a viewModel
ViewModel has some event signals, like the following back event
class ViewModel{
let backSubject = PublishSubject<String>()
}
ViewController has contentView
and viewModel
, and contentView
init with viewModel
lazy var contentView: ContentView = {
let view = ContentView(viewModel)
view.backgroundColor = .clear
return view
}()
and ViewModel's various subject are subscribed in viewController to handle other part view
viewController
is a Dispatch center.
ViewModel
is Event Transfer station. ViewModel
is in everywhere, in Controller, in View, to collect different event triggers.
the code is quite spaghetti
in ContentView
, user tap rx event , binds to the viewModel in viewController
tapAction.bind(to: viewModel.backSubject).disposed(by: rx.disposeBag)
user events wires up easily.
But there is memory leakage actually.
So what's the other disadvantages?
CodePudding user response:
ViewModel doesn't break the Law of Demeter but it does break the Single Responsibility Principle. The way you solve that is to use multiple view models, one for each feature, instead of a single view model for the entire screen. This will make view models more reusable and composable.
If you setup your view model as a single function that takes a number of Observables as input and returns a single Observable, you will also remove any possibility of a memory leak.
For example:
func textFieldsFilled(fields: [Observable<String?>]) -> Observable<Bool> {
Observable.combineLatest(fields)
.map { $0.allSatisfy { !($0 ?? "").isEmpty } }
}
You can attach the above to any scene where you want to enable a button based on whether all the text fields have been filled out.
You satisfy the SRP and since object allocation is handled automatically, there's no concern that the above will leak memory.
CodePudding user response:
You are right, there are some drawbacks, if you want just a data-binding, I would suggest to use Combine
instead, since no 3rd party libraries need, you have it already. RxSwift
is a very powerful tool when you use it as a part of language, not just for data binding.
Some of suggestions from my experience working with RxSwift
:
- Try to make VMs as a structs, not classes.
- Avoid having DisposeBag in your VM, rather make VC subscribe to everything(much better for avoiding memory leaks).
- Make its own VMs for subview, cells, child VC, and not shared ones.
Since your VC is a dispatch centre, I would make a separate VM for your content view and make a communication between ContentView
VM
and ViewController
VM
through your controller.