mutualmobile / Counter

A simple example of the VIPER architecture for iOS apps
MIT License
351 stars 55 forks source link

Example with Data Source et Wireframe #1

Open JeanLebrument opened 10 years ago

JeanLebrument commented 10 years ago

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

cnstoll commented 10 years ago

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,

JeanLebrument commented 10 years ago

Thank you very much !

ghost commented 10 years ago

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

cnstoll commented 10 years ago

FYI - The new article on VIPER that I mentioned for @JeanLebrument is published here: http://www.objc.io/issue-13/viper.html

cnstoll commented 10 years ago

@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.

ghost commented 10 years ago

@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!!!

hugobast commented 9 years ago

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.

hugobast commented 9 years ago

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!

JeanLebrument commented 9 years ago

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.

hugobast commented 9 years ago

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.

fatuhoku commented 9 years ago

:+1: @JeanLebrument would be good to learn more. Nothing would be better than a little toy project.

JeanLebrument commented 9 years ago

@hugobast and @fatuhoku, I will show a little project, but I'm super busy right now with my midterms.

Cheers

hugobast commented 9 years ago

@JeanLebrument Sounds good, I'll keep an eye out. Let us know.

delebedev commented 9 years ago

Hey @JeanLebrument any updates here?

JeanLebrument commented 9 years ago

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 notifications@github.com 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.

JeanLebrument commented 9 years ago

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!

delebedev commented 9 years ago

@JeanLebrument :+1:

hugobast commented 9 years ago

Thanks for doing this @JeanLebrument

JeanLebrument commented 9 years ago

You're welcome! Sorry for the delay!

tar500 commented 9 years ago

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!

membersheep commented 9 years ago

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!

JeanLebrument commented 9 years ago

I'm glad to hear that my contribution helped you guys!

hugobast commented 9 years ago

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.

membersheep commented 9 years ago

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

scottrhoyt commented 9 years ago

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:

Cons:

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.

membersheep commented 9 years ago

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.