Getting Started with the VIPER Architecture Pattern | raywenderlich.com

In this tutorial, you’ll learn about using the VIPER architecture pattern with SwiftUI and Combine, while building an iOS app that lets users create road trips.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/8440907-getting-started-with-the-viper-architecture-pattern

In 5 minutes of test I was able to see 2500+ memory leaks. Not the fault of the author but it’s Apple.
Combine is probably the worst framework they have released. I hope they fix all those issues but until then Combine mustn’t be used in production application.

Thanks for the tutorial it is interesting I was eager to see the result, I was wondering how to make a VIPER stack in SwiftUI.

There is 2 thing2 that bothers me a lot in the placement of some code that (for me) goes against the VIPER principle.
First.
When I do a presenter in VIPER with UIKit, I will not import UIKit in the presenter, just in the View and in the router if there is no global app routing in place.
So when I see SwiftUI being imported in the presenter and the presenter creating and returning views to the view layer, it feels like those method are stealing responsibility from the view. Which breaks the separation between View and Presentation layer.

The second point is similar, when I see code in the presenter creating NavigationLink it feels like the presenter is stealing some of the Routing layer responsibility. Why do the presenter knows that its a navigation link at all.
I know that navigation is weird (at best) in SwiftUI (especially NavigationLink that create the next view right away, instead of passing a factory closure…), but I would at least make the Router create the whole thing and just have the presenter forward the router’s creation instead of having the presenter do some of that routing.

Once again, thanks for the tutorial it was interesting to read the code. It brought me more knowledge about SwiftUI.

P-S: It would be nice / instructive to have some unit test in the final project files to showcase the testable advantage of the architecture.

Please publish one using UIKit , thanks!

Thanks for the feedback. The SwiftUI imports were unfortunate, but I wanted to make sure binding smoother, as well as vending the navigationlinks. It’s really a lot of overhead to have all these separate objects in SwiftUI because the presentation layer is so stateful.

I did originally have a whole unit test section but it went on too long! But by mocking the interactor and presenter layers really makes testing quite clean.

Thanks for the suggestion. I am not sure how many new tutorials will be written for UIKit, but I’ll add it to our backlog.

In the tutorial, I have question regarding the code snippet

interactor.$waypoints
.map {
$0.map {
let annotation = MKPointAnnotation()
annotation.coordinate = $0.location
return annotation
}
}

Why did you use $0.map with in another map?

Thanks for the tutorial, Michael.

I have a question regarding the Data Model. If it is parts of the Entities (which is the most inner layer in clean architecture, why should it be tightly coupled with the persistence (which I believe sits in the most outer layer)? Doesn’t it break the rule of clean architecture where the inner layer should know nothing about the outer layer?

Thanks for your question and welcome to the RW community! This is mostly for convenience. VIPER doesn’t translate well to SwiftUI, so some compromises were made to keep it practical.

@pkprasad You first use the second map(_:) to map each waypoint in waypoints to its corresponding annotation on the map and then use the first map(_:) to map the waypoints array to the pins one.

Please let me know if you have any other questions or issues about the whole thing. Thank you!

Thanks for this tutorial. I’ve noticed strange behaviour on the Trip details view: you can edit the name of the trip (it updates the title as well) and clicking save, calls the right action. But if you navigate back to the list, and back to the edited trip, the old trip name is in the Trip Name Text field (title is correct though).

Is the value binding to the right places?

This is using XCode 13 running on iPod Touch 7th gen

Thank you very much for the tutorial. I find it super interesting. It would be nice to do it with UIKit.

.assign(to: ..., on: **self**) is always dangerous because it creates a strong cycle.
If you want to act on values of self, better use the sink approach with the weak self dance or create an assignWeak variant, wich will cover that self can be weak.