Could you provide a MVVM+RxSwift example?
lts1610 opened this issue · 8 comments
You need to describe me what exactly you want to see in this example? From my understanding route-composer sits aside from the app architecture. If you need to navigate somewhere, you call the router. And you can wrap it in any architecture you want. And call your method/class on top of it. If you need to make some signal at the end of navigation - call it in the completion method of the Router
.
#if canImport(RxSwift)
import RxSwift
extension Router {
public var rx: Reactive<Self> {
return Reactive(self)
}
}
extension Reactive where Base: Router & AnyObject {
func navigate<ViewController, Context>(to step: DestinationStep<ViewController, Context>, with context: Context, animated: Bool) where ViewController: UIViewController -> Observable<Void> {
return Observable.create { [weak base] observer -> Disposable in
guard let base = base else {
observer.onCompleted()
return Disposables.create()
}
do {
try navigate(to: step, with: context, animated: animated, completion: { result in
guard result.isSuccessfull else {
observer.onError(error)
return
}
observer.onNext(())
observer.onCompleted()
})
} catch let error {
observer.onError(error)
}
return Disposables.create()
}
}
}
#endif
I assume it should be something like this. But in general there are thousands of way to implement that. As there is thousands of ways to deal with MVVM. It is an architecture not a pattern. I am not 100% sure what outcome you expect to get in RxSwift. I believe that navigation can be triggered by the view model, but there should be some kind of wireframe object that sticks that whole app together and exposes the navigation methods to the application modules to provide the navigation between them. So basically sits outside of the MVVM architecture.
I seeing that each ViewController
have either a Context
or not. In MVVM, could we consider it as a ViewModel
?
And I have a scenario:
- The
ViewControllerA
have aViewModelA
. TheViewModelA
have areload
PublishSubject. - The
ViewControllerB
have aViewModelB
. TheViewModelB
have aresult
PublishSubject. - In the
ViewControllerA
, a user taps on anext
button, the system navigates toViewControllerB
- The user does something on
ViewControllerB
and the user taps on adone
button, the system navigates toViewControllerA
- The
ViewControllerA
need to reload with the result from theViewModelB
of theViewControllerB
by binding theresult
PublishSubject to thereload
PublishSubject.
@ekazaev Where to place binding the result
of ViewModelB
to the reload
of ViewModelA
?
No, context is some data that you have to pass from one screen to another. While view model is something that represents the whole screen itself.
Lets say you have a product list, and you need to navigate to some specific product screen when user selects it in the list. It mean that the context of the product screen is a product id type. The String
type for example.
Okay, I got it. Please help me to resolve the scenario as above.
I am not sure about your particular view model implementation, but you need to make your ViewModelA
be aware of the actions ViewModelB
. It can be implemented in a lot of ways.
One of them is to pass a subscriber to the events of the ViewModelB
with the Context
. In the example i gave you with authorisation - i pass delegate object as the Context
. Which is basically a subscriber in RxSwift.
But it also depends on what exactly you are doing. It might not be the best option in your case.
What i want to say, that the thing you are trying to solve is not a navigation
issue. Done
button let's say hides ViewControllerB
presented modally. Basically it does dismissViewController(amimated:)
call. Modal view controller can be hidden with the swipe down as well (of course if you'll implement it). So basically here we destroy a view controller, and as a result of this destruction we appear on the ViewControllerA
which needs to update its ViewModelA
.
So it is not exactly an issue to solve with the router
or RouteComposer
. RouteComposer
can be part of the solution, but it might be not if you dismiss modal view controller with the swipe or without using router at all.
This solution should sit somewhere in your business logic. Delegation pattern, RxSwift and so on are the instruments you can use.
You may look on the similar example with the UINavigationController
, You have there 2 view controller A and B, and when user taps Back
button there you need to update view controller A. Also user can swipe back to the A view controller. Neither RouteComposer
nor ViewModlelB
are involved in this scenario. May be in this case would be better to update view controller A on every viewWillAppear
call instead of building the subscriber chain as it wont work in this case. A lot of cases - a lot of possible solutions.