MVC, MVVM, MVP, and similar design patterns are great and each is an improvement on the other, but they still do not scale well for teams larger than 10 or 20 people. If you’re beyond that team size, you need to use a more generic and scalable architectural approach. There is such a conceptual approach, called Clean Architecture.
Clean Architecture is a conceptual application architecture for scale and can be simply described as “an onion layered architecture”. The main idea is to keep dependencies pointing inward towards your domain logic and domain models and keeping everything else pluggable and optional (the way you store data, render ui, receive or send networking requests, etc.). This architecture scales particularly well for large teams of 100+ developers.
There are two concrete implementations of Clean Architecture on iOS: VIPER and RIBs.
VIPER stands for View, Interactor, Presenter, Entity, and Router. Those are the building blocks of that architecture. In this architecture, everything starts with a router and ends with a view. Each VIPER stack (meaning a set of a View, Interactor, Presenter, Entity, and Router) is one screen or one logical UI part of your application. To navigate and use a VIPER stack, you'd instantiate its router and then ask it to create its view controller. The router creates a view controller, a corresponding presenter that formats data for the view and receives user input for the view, an interactor that holds business logic and communicates with presenter, and entities necessary for interactor to work. Then the VC owns presenter, presenter owns interactor, and interactor owns entities and the router. The resulting view controller is used in your view hierarchy and inserted, pushed, or presented as necessary. This architecture allows for strong encapsulation of logic and scalability for team size since every part of your app is now a VIPER stack.
RIBs stands for Router, Interactor, Builder. RIBs is another implementation of Clean Architecture that was an improvement on VIPER. In RIBs architecture, the main building block is a RIB, a set of one router, one interactor, and one builder with optional view and presenter. RIBs without a view are called headless RIBs. Just like in VIPER architecture, you route from one RIB to another using router, and that structures the entire runtime of your app in as a tree structure with parent and children RIBs. Since the view is optional, unlike with VIPER, your application tree structure might or might not mimic your view hierarchy.
Builder is responsible for fetching or creating dependencies for the interactor, router, and the view/presenter assembling and initializing them.
Router is responsible for navigating to specific children RIBs.
Interactor is responsible for all the business logic and initiating routing using router.
Presenter and the view are typically combined in a view controller where presenter is responsible for massaging and formatting data for display in the view.
View is responsible for display data on the screen and collecting user input.