Reputation: 4066
I have a dependency problem with my UIViewController
and my view model.
Basically I want to listen the viewDidLoad
event inside my view model.
At the moment I have a Class A
which instantiates view model and UIViewController
with parameter the viewModel, so:
let viewModel = ViewModel()
let viewController = UIViewController(viewModel)
and I've created a RxCocoa extension for the viewDidLoad
:
var viewDidLoad: Observable<Void> {
return self.sentMessage(#selector(Base.viewDidLoad)).map { _ in Void() }
}
now I'm stuck to bind this rx.viewDidLoad
to an observable inside my view model. I am able to do it with Subjects
but I want a reactive approach using just Observable
.
I know that I could inject rx.viewDidLoad
as constructor parameter of the view model but in this way I'd break my architecture and I don't want to allow the UIViewController
to instantiate the view model internally but I want to keep it as a injected dependency.
Any suggestions? Thanks
Solution
Thank to @tomahh I've used this solution:
My view controller:
override func configure(viewModel: ViewModel) {
viewModel.bindViewDidLoad(rx.viewDidLoad)
}
My view model:
func bindViewDidLoad(_ viewControllerDidLoad: Observable<Void>) {
//Create observers which depend on viewControllerDidLoad
}
Upvotes: 3
Views: 10102
Reputation: 1607
let viewDidAppear = rx.sentMessage(#selector(UIViewController.viewDidAppear(_:)))
.mapToVoid()
.asDriver(onErrorJustReturn: ())
Upvotes: 1
Reputation: 6413
If anybody needs that rx properties here is a ready to use solution, inspired by the code of @marco-santarossa
extension Reactive where Base: UIView {
var willMoveToWindow: Observable<Bool> {
return self.sentMessage(#selector(Base.willMove(toWindow:)))
.map({ $0.filter({ !($0 is NSNull) }) })
.map({ $0.isEmpty == false })
}
var viewWillAppear: Observable<Void> {
return self.willMoveToWindow
.filter({ $0 })
.map({ _ in Void() })
}
var viewWillDisappear: Observable<Void> {
return self.willMoveToWindow
.filter({ !$0 })
.map({ _ in Void() })
}
}
Upvotes: 2
Reputation: 13661
Because ViewController
already knows about view model, it could set a property on ViewModel
at initialisation time
class ViewController: UIViewController {
init(_ viewModel: ViewModel) {
viewModel.viewDidLoad = self.rx.viewDidLoad
}
}
And then, observables in ViewModel
could be defined as computed property deriving viewDidLoad
struct ViewModel {
var viewDidLoad: Observable<Void> = .never()
var something: Observable<String> {
return viewDidLoad.map { "Huhu, something is guuut" }
}
}
Upvotes: 4