Earlier this month, I wrote about validating temporary models for forms. The validation returned .complete or .incomplete, which doesn’t help much when you want to show what did go wrong. So I came up with a richer validation syntax.
Ian Keen posted an article about type-safe temporary models. You would use them like scratch pad contexts in Core Data: in forms, you collect information into these temporary models and then generate your real objects from them.
One thing that repeatedly messes up the conceptual purity of a view model is figuring out which entity should be mutated upon user interaction. Part of this purity stems from the fact that a view model is best served as view data to stress that it doesn’t contain much (business) logic. Making the data mutable introduces a lot of problems figuring out what that view model really is.
One of the commenters nailed it: any MV* variant focuses on architecting view components. Only VIPER takes the application as a whole into account. MVC by itself is an architectural pattern, but not an approach to app architecture in itself.
A UIViewController belongs into the user interface layer and is, in fact, a composite view itself. That’s confusing at first because of the name. This insight will liberate you from thinking that a view controller is sufficient to glue data to UIKit components. There’s room for a whole application between these two.
The VIPER example is exceptionally good. It takes VIPER’s heritage of Clean Architecture and Hexagonal into account and defines the Interactor through an output port. In that way Bohdan’s sample code is more east-oriented and cleaner than what you’d usually find on the topic:
protocolGreetingProvider{funcprovideGreetingData()}protocolGreetingOutput:class{funcreceiveGreetingData(greetingData:GreetingData)}classGreetingInteractor:GreetingProvider{weakvaroutput:GreetingOutput!funcprovideGreetingData(){letperson=Person(firstName:"David",lastName:"Blaine")// usually comes from data access layerletsubject=person.firstName+" "+person.lastNameletgreeting=GreetingData(greeting:"Hello",subject:subject)self.output.receiveGreetingData(greeting)}}
Usually, you’d model provideGreetingData() as a function that returns the data to the caller. This will cause trouble in async processes of course.
You see in the full example that the amount of types seem to explode. Don’t be afraid of that as long as you can assign each type a specific responsibility. Then it won’t turn into the mess everyone seems to be afraid of.
Having used VIPER in apps myself, I see a problem with the names, though. XYZInteractor and XYZPresenter aren’t much better than XYZController in terms of expressiveness. On top of that, a concrete Presenter is always modelled to act as event handler, too. Don’t let this fool you into thinking you absolutely have to do this yourself – there’s always room to separate writing from reading operations, or event handling from view population.
From the department of Domain-Driven Design code patterns, I today present to you: well-named value objects! You can go a lot farther than you have previously imagined with value objects in Swift. Now that Swift is more than a year old, most of us have seen the use of struct and heard how useful passing objects by value is.