Question

I am trying to implement VIPER architecture on iOS in Swift.

The problem I have is how to set up the object graph. Please ignore the Router and the Entity as it is not relevant to my problem. That leaves us with the Interactor, Presenter, and the View.

Interactor - business logic, has state, does work, accepts commands. Presenter - transforms abstract data to presentation format, or ask interactor to do work. View - presents presentable info, sends actions to Presenter to translate to business logic requests.

The communication between these three components is bidirectional and the Interactor and View are not aware of each other:
Interactor <-> Presenter <-> View.

All are defined as protocols. (interfaces in other languages...) Each concrete component conforms to its corresponding a protocol (i.e. implements an interface)...and those components only see each other as interfaces.

Here comes the problem:

For the presenter to work correctly, it simply has to have a reference to an Interactor instance where the business logic and state sits. Same goes for the View, it cannot work correctly without a reference to a properly initialized Presenter instance.

I have two options:

OPTION A: 1) The presenter will have a required initializer which will take in an interactor instance. 2) The view will have a required initializer which will take in a presenter instance. 3) I will enforce this in protocols.

OPTION B: 1) There will be a public .interactor variable on the presenter, and this will be settable on a presenter instance. 2) There will be a public .presenter variable on the view, and this will be settable in a view instance.

Option A with initializers gives me a mechanism that ensures things are set up in the right order and they are initialized to a valid state. However, this leads to having to replicate the same mechanism in unit testing where mocks, stub implementations of those protocols actually have to have those initializers and initialize with each other..that means now I have a chain of mocks depending on each other which smells.

Option B prevents the problem with a chain of mocks, but then I will potentially have objects in invalid state, or I have to actually unit-test the router methods that sets up the dependency chain. But then I will be able to only deal with one layer of mocks for each unit test case. At least in theory I think, I haven't try that yet.

Which approach is correct? Or is there some other approach? Can you advise please?

Was it helpful?

Solution

The dependencies of your concrete Presenter on an Interactor instance and of your concrete View on a Presenter instance are not dependencies that are inherently part of the respective interfaces.
Rather, they are requirements from your concrete implementation classes.
For example, a mock Presenter can perfectly well do its job without having an Interaction instance.

This means that the correct implementation would be close to your option A, but without placing this requirement in the protocols.
That way, it is impossible for the Router (which needs to know the concrete classes anyway if that is where the Presenter and View get instantiated) to create a View or Presenter without the required links, but you avoid the chain of dependencies in your tests.

Licensed under: CC-BY-SA with attribution
scroll top