The preface
Learning is like rowing upstream; not to advance is to drop back. Mutual encouragement!! If you want to become a machinist, sink your heart into this article. Don’t say you read this article, how will, but at least not let you read this article is equal to waste life. Let’s cut the crap and get straight to the dry stuff.
MVC
If you want to be an anonymous architect, the first thing you need to know is that MVC, classic is classic, there’s no one, because it’s classic for a reason. MVC architecture in iOS, understand Stanford university professor white beard this picture is basically ok.
The Controller object owns the View and the Model object, and they communicate with each other through the Controller. Three classes for a single page feels simple.
Where do Internet connections go? In the Model? Makes sense? In fact, a lot of network connection initiation and receiving processing is put in the Controller for convenience. Models typically have only property definitions, not implementations.
The View should be a separate View, right? In fact, most of the views are in the Controller, and there’s a loadView function, which is pretty handy. How many people would write a separate class for a View?
Originally, XIB and Storyboard are good ways to separate views. However, due to “not suitable for multi-player collaboration, version management”, not to code writing interface, but also the words: “high performance, good for training new people”. “A lie can be told 100 times,” especially when the reasons sound plausible.
Where do things like “Check username is valid, check password is correct” go? How many people start a new class like the Stanford guy with the white beard? It’s basically done in Controller.
BaseController, BaseView, BaseModel you’ve seen a lot of them? Some of them have several layers public View, various names common or something like that common class? The network connection, database, logic and so on are often much more than the View itself, like a small module, more powerful than the Controller. Is this still a View?
MVC is the simplest architecture in theory, but in practice it turns out to be the most difficult architecture. Controller becomes god, doing everything. “I know that piece of shit works, but I don’t know that it’s simple MVC.”
MVC is also known as a Massive View Controller. It’s not MVC’s fault, it’s just that no programmer admits to being lazy and having bad programming habits. With programming habits as good as Stanford’s white beard, most iOS apps have a clear MVC architecture.
MVVM
MVVM comes from MVC, and a classic diagram is the one below, seen in many articles.
“Consider for a moment that while the View and View Controller are technically different components, they almost always go hand in hand, in pairs. When do you see a View pairing with different View Controllers? Or vice versa? So why not normalize their connection?” —— this paragraph gave me a deep impression at that time, and I agree with it till now. Controller represents the life cycle of a Scene and is a scheduler. Everything is, because nothing can do without it. It’s like nothing, because it doesn’t represent anything concrete. Putting it together with View gives it concrete meaning as a generalized View and limits the impression that it can do anything. This deserves recognition.
Presentation Logic can be moved from the Controller to the ViewModel to reduce the burden on the Controller. I also support this view. And I think of the ViewModel as doing “display logic,” one page at a time, depending on the page. In Swift, I use structures for viewModels.
For binding mechanisms, ReactiveCocoa is recommended in the article. I went to have a general look, and it mainly unified various communication mechanisms such as KVO, Block, Notifification, delegate and so on into RACSignal, and bidirectional binding between interface and data is really powerful. However, this style is far from normal iOS development habits, and it is difficult to change. The article also said that it is only recommended, not mandatory, so I have not used. Misunderstood MVC and deified MVVM
As for the binding mechanism, you can use attribute observers in Swift. The ViewModel is usually a property of the Controller, you observe it, and when it changes, you set the interface element with the new value of the ViewModel, and it feels good to use. There are also some changes that are far apart or one-to-many, which can be achieved by NSNotifification.
Where should the business logic (as opposed to the display logic) be for fetching data from the network? The article doesn’t say, look, it means keep it in Controller. There’s also the idea that you should put it in the ViewModel, which is certainly true, and that’s the mainstream understanding. But that would make the ViewModel another God class.
I understand MVVM
This is my understanding, only one opinion. The prevailing view is that there is no Logic class, which is basically removed from the diagram. ViewModel is going to be a God class in place of Controller.
The Controller, as the scheduler, is at the center. View-related functions: for example, animations that change the position of the View are stored in the Controller. This is also consistent with the concept of Controller+View implementing View functionality. Viewmodels specialize in “display logic” and use property observers for bindings, Notifification if necessary. Positive bindings, such as the “action-target” response, are kept in the Controller, leaving the work to other classes.
In Swift, viewModels and models recommend structs; Logic tends to use class. From a simple and intuitive concept, the ViewModel needs to stay lightweight, follow the page, and be ready to change. The Model is also lightweight, just a data structure, ready to change, following the dictates of the backend API. Logic is relatively large, consider stability, consider reuse.
Add Logic class, responsible for business Logic, such as fetching data from network, modifying database, checking the validity of user name, specific response Logic, specific processing after listening and so on
- Ape question bank iOS client architecture design
The DataController in this paper is equivalent to Logic here. The focus is on reducing the load of Controller, trying to play the role of scheduler, and handling specific work in Logic. Logic considers reuse. It can correspond to a single page or share multiple pages. Divide modules according to business logic. The classification criteria can be different from the page classification criteria. For complex pages, you can have multiple views and ViewModels, and think of them as components. For tables, the ViewModel corresponds to the table’s cell. The dataSource array contains the ViewModel sequence. The delegate and dataSource of the table are, by far, the most convenient in the Controller. Of course, it’s a good idea to add a TableDelegate class to lighten the load on the Controller. If the table is contained within a component, using the container View as a delegate and dataSource is a good choice. The main idea is to try to “empty” the Controller so that it is only a scheduler, managing the life cycle of the page. Let it do specific things only when it is absolutely necessary. Do not introduce large third party libraries such as ReactiveCocoa. Here is a good article worth studying.
ReactiveCocoa and MVVM starter VIPER
This is a finer schema than MVVM classification.
Classic graphics
-
Present: equivalent to a ViewModel, called a presentation
-
Interactor: an Interactor that focuses on business logic; Fetching data from the network, database and so on are all here.
-
Entity: Just a data definition
-
WireFrame: is a Router, which is a page redirect
Something worth learning
Separate the page jump and make it a common module
Separate the business logic into common modules
If there are so many classes for a single page, it feels a bit wordy. Not enough for multi-page modules, there is still borrowing
As a meaningful
Other architectures
Some schemas are actually in use, but there is no common abbreviation
Layered model
PNG hierarchical architecture
The concept of a service, service, is introduced to the client as an intermediate layer for isolation
As a service module, the business logic is accessed as a service
The data access is separated from the business logic, and the presentation layer is separated from the interface layer of the background. The presentation layer only focuses on THE UI, which is equivalent to V and P in VIPER. Or the ViewModel in MVVM (showing only logic) and
View, but no bidirectional binding;
The platform
At present, most apps are a mixture of Native and H5. It is a good practice to unify the interface codes of both into common modules. Plug-in is also an increasingly common trend, such as sharing, third-party login, payment and so on, which are all provided by third parties in the form of plug-ins. Centralized management of these plug-ins is also good practice
With the development and expansion of the company, different business units are divided into multiple APPS or different businesses in the same company. So there are two opposite trends: on the one hand, you want to share modules and have multiple businesses share them; On the other hand, their business and isolation, independent development. The company may also set up a public platform division. There is a vertical split between business units; There is a horizontal split between the business and the platform. This leads to a three-dimensional architecture divided into two dimensions.
- Separate out of boundary surface layer, as thin as possible, cooperate with UI students, fast strain
- Separate the data layer as thin as possible, cooperate with the background, and adapt quickly
Some think
There is no unified standard for architectural design. All the architectural models mentioned above have positive reference significance, but they should not be copied. Need to be
Make trade-offs according to your actual situation
- Step0: platform application
The master App calls the child App in the form of a URL
The form is similar to calling, texting, emailing
The definition of URL needs to be considered
- Step1: vertical division
It has three parts: Native, H5 and plug-in
A unified bridge module is provided between Native and H5
A unified bridge module is provided between Native and the plugin
If ReactNative is added, bridge modules between Native and ReactNative should also be provided. This one can be reserved,
You can also add them later.
- Step2: Horizontal division
The Native section is horizontally divided because it is the most resource-intensive section
-
- The top layer is the interface layer (which can be called the presentation layer or the UI layer), where MVVM ideas can be borrowed. M is provided by the lower layer as a service. VM just does display logic, struct in Swift. This layer is the communication layer with the product, as thin as possible, and can respond to changes quickly. All functions that can be given away, such as business logic, should be given away. The core and the point is to make the Controller only the scheduler and, if necessary, participate in a small part of the View.
-
- At the bottom layer is the Micro Service layer. This layer provides basic functions such as networking, caching, encryption and decryption, system information, logging, statistics, and so on. The concept of microservices is that they can only be called by other modules, not the services of other modules. Modules in this layer cannot call each other either. Here are some basic components, divided by function, with isolation being the first consideration. Requires high cohesion.
-
- In the middle is the Service layer, where services can call microservices and each other.
It’s easier to have three layers. Of course, it can also be divided into some interface layer, service layer can also be divided into common service layer, business logic layer, etc. This can be configured flexibly as needed. But generally there are three layers (interface, services, microservices). Do not call across layers; the interface layer can only call services provided by the service layer. The service layer can do the work itself, or it can call other services or microservices to do the work.
-
Step3: Division within layers
-
Interface layer: Organized by page, providing common UI components, which can be understood as (M) VVM. VM acts as a medium to transform “interface display” into “data manipulation”, using Swift’s attribute observer feature for level 1 binding. Do not introduce large third-party libraries for functional programming such as RxSwift.
-
Service layer: it is divided into public service, jump logic, business logic and other modules according to logical functions. Interfaces to the interface layer are protocols defined for each ViewModel class, regardless of the specific page.
-
Micro service layer: divided by function, without designing business logic, divided into network, database, encryption and decryption, log, statistics and other function frame diagram
The language is Swift, iOS8 is the lowest supported version, and iOS9 is selected conditionally
Both services and microservices are provided in the form of a framework, and isolation between modules is a major consideration.
Services and microservices are only logical hierarchies. In terms of the specific engineering organization, they both use level 1 framework encapsulation
The hierarchies and calls between each other are implicitly represented by dependencies between each other. Provides an interface – isolated service.framework that is only called by the interface layer to accomplish all tasks. Function equivalent to
Foundation.
The project is organized in the way of workspace, and the third-party management tool adopts Carthage. Conditional, microservice as well as ministry
Sub-services can be in the form of private Carthage, which is easier to reuse.
Plug-ins are also required to be provided in framework form and do not accept static libraries of. A.
If you need to use Object-C, C and C++ temporarily, all of them will be unified into the form of the framework and replaced by Swift gradually in the future.
The class diagram
- Interface layer
AppDelegate and ViewController exist only as schedulers and do nothing concrete. The ViewModel does nothing more than display logic and simply transforms the interface into data. With structs, each member is a normal variable and has a default value that represents the determinism of the page. A ViewModel is a data structure that does the job of displaying logic.
UI components consist only of View and ViewModel, which can only contain display logic, not jump logic, business logic, etc.
Both the UI layer and the Service layer make sense: the UI layer represents display logic; The Service layer represents the data interface between the UI and the Service. On second thought, I decided to put it in the UI layer. The ViewModel’s best use is to turn UI changes into data operations, essentially closer to the UI.
As for the interface between the UI layer and the Service layer, it is better to define the relevant ViewModel Protocol. These Protocol definitions are placed in services (due to the framework’s influence), putting some of the basic requirements of the ViewModel in Protocol. The service satisfies the protocol with a Model or something else. Using Protocol as an interface is better than simply using Model. Because Model changes with background API definitions, Protocol is a base class with more flexible types.
In addition to defining a protocol for the ViewModel, define a protocol for the Service.
The interface layer remains the lightest. Page jump logic, specific business logic and other work all down to the service layer to do. ViewModel is a struct, mainly do display logic, the concept is relatively small, generally a page one or more. A service is a class that can be shared by multiple pages. The scale can be flexible according to the specific situation. Different pages are distinguished by extensions that follow different protocols. The class itself may be large, but each part is relatively small.
- The service layer
The service.framework exists as an adhesive layer, and AppDelegate and ViewController can simply import Services
The related service is invoked.
Service specific logic such as finance, framework, insurance, and framework Router, user, and sharing are service independent public logic
Each module in the layer can call each other the concrete existence form, singleton, class, or framework, etc., can be flexibly decided according to the specific situation. For clarity, only a small portion of the call relationship lines in the figure are drawn and most of the lines are left out.
- Micro service layer
From the perspective of development, according to the functional classification; It is a technical language that engineers communicate with each other, rather than a business language that communicates with the product. It has high cohesion, and as the basic module to be called, there should not be a relationship between modules that calls each other, which exists in the form of a framework. High cohesion, high reuse.
conclusion
This is a bit of a take-home message, and maybe you’re interested in the architect. If it helps you, give me free likes and followings. Finally, let’s give you a wave of information. I hope I can help you.
Books: Download address