nimblehq / VIPER-Templates

Xcode files templates for various parts of VIPER module
5 stars 1 forks source link

Inject Router and Interactor in Presenter's init #20

Closed teamdisc closed 4 years ago

teamdisc commented 4 years ago

The last thing I'd like to bring up is what we discussed 2 weeks ago.

So I think we might not need Interactor and Router to be optional in Presenter. This is what we currently have

final class SomePresenter {

    weak var view: SomeViewIntput?
    var router: SomeRouterInput?
    var interactor: SomeInteractorInput?

    weak var output: SomeOutput?
}

It's not really a big deal here tho, but the problem here is that we need to guard let our interactor when using it. In most cases, it would be fine as we could just make it like interactor?.doSome() here. But sometimes, we might need to use our interactor to validate some condition like

func doSomethingOnSomeCertainCondition() {
    if let interactor = interactor, interactor?.isSomethingValid {
        print("do something")
    }
}

While it might be a bit more straightforward if we could do something like

func doSomethingOnSomeCertainCondition() {
    if interactor.isSomethingValid {
        print("do something")
    }
}

The way I see it is that, since Interactor and Router are gonna be strongly captured by Presenter anyway. Maybe we could just inject them in the first place

final class SomePresenter {

    let interactor: SomeInteractor
    let router: SomeRouter

    weak var view: SomeViewInput?
    weak var output: SomeOutput?

    init(interactor: SomeInteractor, router: SomeRouter) {
        self.interactor = interactor
        self.router = router
    }
}

The downside for this one, IMO, is that we might have a bigger init function that we usually have. But I think, in most cases, Presenter doesn't really have many dependencies anyway as they are likely to be in Interactor layer.

Let me know what you guys think about it 🤔

nmint8m commented 4 years ago

@teamdisc For me, I quite agree with this approach because it reduces the unwrap expression inside the Presenter. I also want to move the initial setting (* and **) into the Presenter initializer. What do you think about it?

final class SomeModule {
    let view: SomeViewController
    let presenter: SomePresenter
    let router: SomeRouter
    let interactor: SomeInteractor

    ...

    var input: SomeInput {
        return presenter
    }

    init() { 
        view = SomeViewController()
        router =SomeRouter()
        interactor = SomeInteractor()
        presenter = SomePresenter(interactor: interactor, router: router)

        view.output = presenter
        presenter.view = view
        // What do you think about moving * and ** into presenter?
        // interactor.output = presenter // *
        // router.view = view // **
    }
}
final class SomePresenter {

    let interactor: SomeInteractor
    let router: SomeRouter

    weak var view: SomeViewInput?
    weak var output: SomeOutput?

    init(interactor: SomeInteractor, router: SomeRouter) {
        self.interactor = interactor
        interactor.output = self
        self.router = router
        router.view = view // *** Related to issue 19th
    }
}
nmint8m commented 4 years ago

The main reason is that I want to keep the setting in one place, it's easier to trackback where we did set delegations between Presenter - Interactor, Presenter - Router and Router - View...