I am learning Viper
w/ RxSwift
.
I would like to notify my Presenter
that viewDidLoad
was called in my ViewController
.
To do this I have the following:
class LoginPresenter {
weak var view: LoginView?
var interactor: LoginUseCase?
var router: LoginRouter?
private(set) var viewDidLoad = PublishSubject<Void>()
private lazy var disposeBag = DisposeBag()
required init(view: LoginView?, interactor: LoginUseCase?, router: LoginRouter?) {
self.view = view
self.interactor = interactor
self.router = router
viewDidLoad
.subscribe(onNext: { _ in
// do something on viewDidLoad
}).disposed(by: disposeBag)
}
}
class LoginViewController: UIViewController {
var presenter: LoginPresenter?
override func viewDidLoad() {
super.viewDidLoad()
presenter?.viewDidLoad.onNext(())
}
}
Once my view is loaded I am calling presenter?.viewDidLoad.onNext(())
I am then able to trigger any actions within my presenter, such as calling out to my router
to ensure navigation is configured or my interactor
.
Should I be using a PublishSubject
for this? Or does RxSwift
have a better suited type?
I feel like this approach means I will end up with something like
viewDidLoad
.subscribe(onNext: { _ in
self.router?.viewDidLoad.onNext(())
}).disposed(by: disposeBag)
Hmm... A Presenter's job is to gather up user actions and I'm not so sure we should consider viewDidLoad a user action. And in any case, the Wireframe (which handles routing) shouldn't need to know when viewDidLoad is called in the first place; its job is to present new screens and you can't present a screen in viewDidLoad.
That said, you can setup your connection in the ViewController's presenter didSet:
final class ViewController: UIViewController {
var presenter: Presenter? {
didSet {
guard let presenter = presenter else { viewDidLoadDisposable.dispose(); return }
viewDidLoadDisposable.disposable = rx.methodInvoked(#selector(viewDidLoad))
.map { _ in }
.bind(to: presenter.viewDidLoad)
}
}
let viewDidLoadDisposable = SerialDisposable()
deinit {
viewDidLoadDisposable.dispose()
}
}
final class Presenter {
let viewDidLoad = PublishSubject<Void>()
}
In general though, it is in the viewDidLoad where the presenter and viewController elements are normally bound together so the above code has a pretty unnatural feel.
Also, Observables, Subjects and the DisposeBag should not be var
s, use let
s instead. That's the "functional" part of functional reactive programming.