Example with Data Source et Wireframe
Hi,
First of all, I would say big thanks to those which wrote this article and carried out VIPER architecture, this is really great.
I try to implement VIPER architecture for my app but I would have an example on how implement Wireframe and Data Source.
In your article on your blog, you said that you will add a new example with Wireframe and Data Store soon ? When will it be available ?
Best regards, Jean Lebrument
Hey Jean,
Glad to hear that you've been finding this helpful! I know some work is being done on an updated example. I believe we'll have more information on that to share soon!
Thanks,
- Conrad
Thank you very much !
Hey,
I wanted to ask, if I want to send some data from one viewcontroller to another, how do I send it using the VIPER architecture?
Thanks
FYI - The new article on VIPER that I mentioned for @JeanLebrument is published here: http://www.objc.io/issue-13/viper.html
@shwetsolanki with VIPER you sort of lose the concept of transferring data between view controllers and replace it with the concept of transferring data between screens. There are certainly cases where data needs to make it from one screen to another, such as to populate an edit screen to modify a selected item. In this case, the two presenters for the respective screens have to work together to identify the piece of data from one screen, possibly modify it to make sense to the other screen, and pass that along when the second screen gets displayed.
@cnstoll Thanks a lot. It would be great if you guys could add this to the To Do example. Passing the selected ToDo from one screen to another and showing a detail todo screen. I know it doesn't make much sense functionality wise, but will clear the doubts of many others.
Cheers!!!
Allow me to put a :+1: to the previous commenter, I figured my own way of passing stuff view to view but I am dying for an authoritative example on this.
I'll put my way of doing it could lead to a discussion (it's ok if it doesn't or if the example gets shot down). Let's imagine a table view for which tapping a row segues to a detailed view of that item:
From the List Wireframe
class SomethingListWireframe: NSObject {
weak var controller: SomethingListController?
func presentSomethingListInterface(parent: UIViewController) {
// ... wire up the VC -> Presenter -> Interactor, etc
}
func presentSomthingDetailInterface(selection: Thing) {
let wireframe = SomethingDetailWireframe()
wireframe.presentSomethingDetailInterface(controller!, thing: selection)
}
}
Then in the Detail Wireframe
class SomethingDetailWireframe: NSObject {
func presentSomethingDetailInterface(parent: UIViewController, thing: Thing) {
let controller = SomethingDetailController()
let presenter = SomethingDetailPresenter(thing: Thing)
// ... wire up the VC -> Presenter -> Interactor, etc
parent.navigationController?.pushViewController(controller, animated: true)
}
}
Of course this entails that something on the list side holds a reference to the list wireframe, I think I went with the presenter, so messaging goes: Cell -> ViewController -> Handler (presenter really) -> InteractorInput -> InteractorOutput (presenter again most likely) -> Wireframe with the Interactor being completely optional depending on the use case.
Good/Bad/Ugly? Let's have it!
I worked on a complicated project as lead iOS developer and we developed the whole project using VIPER architecture.
To pass data from one module to an other, we decided to add a class to each module called "module i/o" which aims three goals.
First one, instantiate the whole module and connect classes together. The second one, is to manage the "parameters" needed in input so that the module works normally. The last one, manage the output of the module and permits to instantiate an other module (by instantiating the "module i/o" class of the next module) and give him needed parameters.
Another interesting thing with the "module i/o" class is you can easy extend it by creating a subclass to change the output module instantiated and the rest of the module (wireframe, presenter, view, interactor, data store and entities) are totally non-dependent of the "module i/o" class.
Moreover to navigate between modules, we used JLRoutes.
If you are interested I give you more explanations about it.
I would be very glad if I can have some feedbacks about my solution.
Hi @JeanLebrument thanks for responding! The module approach you describe was the next logical step for me. I am waiting to feel some kind of pressure to move me toward it, it feels like a good thing. I would be very interested to know more about your approach for sure.
:+1: @JeanLebrument would be good to learn more. Nothing would be better than a little toy project.
@hugobast and @fatuhoku, I will show a little project, but I'm super busy right now with my midterms.
Cheers
@JeanLebrument Sounds good, I'll keep an eye out. Let us know.
Hey @JeanLebrument any updates here?
Sorry dude, I was really focus on my exams and I totally forgot answer to this issue after! I will do it right now.
On Thu, Apr 23, 2015 at 8:14 AM Denis Lebedev [email protected] wrote:
Hey @JeanLebrument https://github.com/JeanLebrument any updates here?
— Reply to this email directly or view it on GitHub https://github.com/mutualmobile/Counter/issues/1#issuecomment-95621335.
I just finished to code an example with a class diagram: https://github.com/JeanLebrument/iOSModuleArchitecture
The architecture looks overkill for the type of project, but in a large scalable project with a lot of interaction between modules which need to be abstracted, this architecture permits to maintain a high level of scalability.
Feedbacks are welcomed!
@JeanLebrument :+1:
Thanks for doing this @JeanLebrument
You're welcome! Sorry for the delay!
Hi @JeanLebrument, @garnett and @hugobast
Almost a year ago I have also made my own version of Counter app with some architectural an file structure changes, that allowed to create/use modules with ease: https://github.com/tar500/viper-counter-app
Also I made my own Objective-C template for vipergen that I used for creating a Counter app modules: https://github.com/tar500/viper-module-generator
This template already includes a lot of boilerplate code, so you can start to add your own code right away. Also there's plenty of helpful comments that help you to think less about what to do.
I would like to know if I didn't mess up the original idea of VIPER, so any feedback is really appreciated!
I would like to thank everybody for the helpful discussion. I'm building a small app to learn to use VIPER architecture and I encountered the same problems that @JeanLebrument solved with the Builder and the IO elements. Giving the responsibility to fulfill those goals to the wireframe seemed wrong and I was theorizing the same solution myself. @tar500 your generator seems cool, I hope I have the chance to try it soon!
I'm glad to hear that my contribution helped you guys!
Just a quick update from me here, random thoughts really:
I am moving away from presenters being required objects always. What I do now at the start of a new module is have that be an interface that the Wireframe will implement. Otherwise I end up with a presenter that's managing the view and a wireframe that's only ever used for segues. I usually name a protocol after the module's name. It's all fuzzy still for me. Really I am just scaling it down a little because starting a module is so much overhead that I started hating it.
All that being said I would totally introduce a presenter object and have that object implement the module interface if the wireframe gets messy.
Other random thought, I'm fine with the wireframe knowing about everything by name, but nothing should know about the wireframe only the protocol it implements (exception being either the AppDelegate or other the RootWireframe if you have one of those). Other than that it's on a case by case basis. At first I overused protocols and there was really no reason for it.
I think that as long as you have a user interface for a module, the module should have a presenter to present and to control it (so it is usually required), and if the module is connected to other modules it should have a wireframe to handle this routing (but it handles the routing, nothing else). I understand that in smaller projects the overhead of decoupling like this may seem wasted time, but I think that when one is used implement the architecture everything becomes fast and easily testable
Just to add my quick 2 cents (feel free to respond with questions).
I have mostly abandoned the VIPER architecture. Here's how I felt about my experience.
Pros:
- Presenter - This is the biggest advantage of the architecture. Getting that code out of the VC makes everything more manageable, testable, and maintainable.
- Interactor/Entities - The distinction between entities and interactor data structures helps keep things like core data and other data services from creeping into view code and making things messy.
Cons:
- Too many objects. So many times the interactor and presenter are doing too little work to justify. Writing unit tests for these objects becomes tedious and not useful as well.
- Viper modules tend to make my think about my code as silos. This has advantages, but I found it worked against me writing reusable code. Sometimes I code get an interactor to be reusable, but this required a good deal of subclassing and adapters to also have the specific interactors conform to module-specific interactor protocols. Simple things became a lot of boilerplate quickly.
- Wireframes are poorly defined currently. They seem to have the responsibilities of both routing and module assembly. Routing is a good concept when you outgrow storyboards, but module assembly is handled better by DI frameworks in my opinion.
- Inelegant model if you are working with some services. In particular, I love Parse. When using Parse with VIPER, I have to either give up a lot of the niceties of Parse, or come up with other additional mapping schemes to recover functionality at the interactor/presenter barrier. This is mostly because of the two different methodologies at play in VIPER and Parse. A Parse object encapsulates most of the business logic of the data object into the data object itself.
- Asynchronous code is more difficult. If you need to have an asynchronous data operation, it should manifest in the land of entities/interactor. But that asynchronous operation now often becomes an asynchronous interactor method and an asynchronous presenter method. If you use another data manager object in the entity layer, this is a third asynchronous operation. Testing asynchronous operations is not trivial and with VIPER I find myself writing 2x the tests and usually for passthrough methods.
- Inter-module communication is not well defined at all.
In short, I find the architecture to be too rigid. I wind up with too much boilerplate code, not enough reusable classes, and hacked together intermodule communication. The effort does not seem worth it for small apps, and for large apps, the abundance of trivial objects, lack of reusable code, poor intermodule communication standards, and non-trivial coexistence with DI frameworks and back end frameworks makes it's usefulness suspect.
I vote to keep the one concept that I really find useful (presenters) and throw the rest out. This makes the architecture look a lot more like MVVM.
Cheers
Edit:
This is from my experience writing an app with 12,000 lines of code with VIPER. Without VIPER, I believe the app would have been < 10,000 LOC.
Thank you Scott, your answer is very interesting, it confirms my doubts. Maybe the lack of strict boundaries (in wireframe and intercomunication) in some modules of the architecture is done on purpose to make those parts more flexible, but I found it a little confusing.