History of the Misunderstood Mvcmvc
MVC, the full name of the Model View controller, is the abbreviation of the models-view-controller. It represents a common framework for client software development.
The concept of MVC first appeared in the the 1980s Xerox Parker Labs (yes, the lab that invented the graphical user interface and mouse), when Xerox Parker invented the software design pattern for Smalltalk.
Now that MVC has become the mainstream client programming framework, in IOS development, the system has implemented common view classes for us: UIView, and Controller classes: Uiviewcontroller. Most of the time we need to inherit these classes to implement our program logic, so we almost evade the design pattern of MVC.
But, decades later, have we really used the design pattern of MVC? Not really, MVC is a layered approach, although it is clear, but if used improperly, it is likely that a lot of code is concentrated in the Controller, so that the MVC pattern into the Massive View Controller mode.
How does a Controller's bloated problem solve?
Many people try to solve the problem of the Controller being bloated under the MVC architecture. I remember half a year ago when InfoQ made a mobile symposium, when Beeframework and Samurai-native's author Lao Guo asked me a word: "What kind of content should be put in the Controller?" 」。 But because of the lack of time, I did not start my point of view, this time right here to talk about my thoughts on this issue.
Let's look at the features of MVC's architecture. In fact, design patterns are often Don‘t repeat yourself
done for the sake of principle, which requires reusable code to be reused as much as possible to ensure reuse. In this design pattern of MVC, we find that both View and model conform to this principle.
For the view, if you are well-abstracted, the animation of one app can be easily ported to other apps, and Github has a lot of UI controls that are nicely packaged in the view layer, making it easy to open source for reuse.
For Model, it is actually used to store the data of the business, and if done well, it can be reused easily. For example, when I was in the Youdao Cloud notebook IPad version, we directly and the IOS version of the code to reuse all the Model layer. The Model layer code for IOS and IPad was re-used again when starting a business as an ape-bank client. Of course, because it is related to the data meaning of the business itself, the reuse of the Model layer is mostly within a product and is unlikely to be open-source to the community like the View layer.
After talking about the View and Model, let's think about how many controller,controller can be reused? After we have finished writing a Controller, can we easily reuse it? The conclusion is: very difficult to reuse. In some scenarios, we may be able to addSubViewController
reuse the Controller in such a way, but its reuse scenario is very, very few.
If we can realize that the code inside the controller is not reusable, we know what code should be written in the controller, which is the code that cannot be reused. In my opinion, the Controller should only store these reusable code, which includes:
- When initializing, the corresponding View and Model are constructed.
- Monitor the events of the model layer and pass the data from the model layer to the View layer.
- Listens to the event of the view layer and forwards events from the view layer to the Model layer.
If the Controller has only the above code, then its logic will be very simple, and it will be very short.
But it's hard to do that because there's a lot of logic that we don't know where to write, so we're all written in the Controller, and then we'll see where the rest of the logic should be written.
How to thin the body of viewcontroller?
Objc.io is a very well-known IOS development blog, the first lesson in the above "lighter View Controllers" on a lot of such skills, we first summed up its views:
- Separate the UITableView Data Source into a different class.
- Separate the logic of data acquisition and transformation into another class.
- Separates the logic of the assembled control into another class.
Do you have any idea? In fact, MVC is only three layers, but it does not limit you to have only three layers. Therefore, we can extract the Controller's overly bloated logic to form a new reusable module or architecture hierarchy.
My personal abstraction of logic has the following summary.
Abstracting a network request into a separate class
The new handwritten code, directly in the Controller with a afnetworking to send a request, the requested data is passed directly to the View. Get started some of the students, know to move these request code into another static class inside. But I don't think it's enough, so I recommend encapsulating each network request directly into a class.
Encapsulating each network request as an object is actually using the Command pattern in design mode, which has the following benefits:
- Isolate network requests from specific third-party libraries, and easily replace the underlying network libraries later on. In fact our IOS client was originally based on ASIHTTPRequest, and it took us two days to switch to afnetworking easily.
- It is convenient to handle common logic in the base class, for example, the data version number information of the ape question Bank is processed uniformly in the base class.
- It is convenient to handle caching logic in the base class, as well as some other common logic.
- Facilitates the persistence of objects.
If you are interested, you can look at our company's Open source IOS network library: Ytknetwork. Under the guidance of this kind of thinking, not only the Controller in the code to thin, and further evolution and strengthening, now it also supports such as complex network request management, breakpoint continuation, plug-in mechanism, JSON legitimacy check and other functions.
This part of the code is stripped out of the controller, not only simplifies the logic in the controller, but also achieves the network layer code reuse effect.
Abstracting the interface's assembly into a specialized class
New handwritten code, like in the Controller to put a UILabel, Uibutton,uitextfield self.view
up the addSubView
way to put. I suggest that you can split the code from the Controller in two ways.
Method One: Construct specialized UIView subclasses to be responsible for the assembly of these controls. This is the most thorough and elegant way, but a little more troublesome is that you need to take over the event callbacks of these controls first and then expose the Controller back to you.
Method Two: With a static Util class, help you do UIView assembly work. This approach is slightly less thorough, but relatively simple.
For some UI controls that can be reused, I recommend using method one. If Project engineering is more complex, I also suggest using method one. If the project is too tight and the code for the related project is not too much, you can try method two.
Construction ViewModel
Who says MVC can't use ViewModel? The advantages of MVVM are as good as we can learn. The practice is to Viewcontroller to View the process of passing data, abstracted into the process of constructing ViewModel.
After this abstraction, View only accepts ViewModel, and the Controller only needs to pass ViewModel such a line of code. In addition to the process of constructing ViewModel, we can move to another class.
In practice, I recommend that you specifically create a construction ViewModel factory class, see Factory mode. In addition, data access can be specifically pumped to a Service layer, which provides ViewModel access.
Specifically constructs a storage class
Just said ViewModel's structure can draw to a Service layer. Accordingly, the storage of data should also be done by specialized objects. In the Little Ape Search project, we have a class called useragent, dedicated to handling local data access.
With data access in a dedicated class, you can do extra things for access. Like what:
- Add cache to some hotspot data
- Handling data migration-related logic
If you want to do something finer, you can abstract the storage engine another layer. This allows you to easily switch the underlying storage, such as switching from SQLite to Key-value's storage engine.
Summary
By extracting the code, we can further split the Viewcontroller in the original MVC design pattern, construct the network request layer, ViewModel layer, Service layer, Storage layer and other classes to work with the Controller, so that Cont Roller is simpler and our App is easier to maintain.
In addition, I do not know that we notice that the controller layer is very difficult to test, if we can be able to thin the controller, it is more convenient to write Unit test to test various interface-independent logic. The Mobile Automation test framework is not very mature, but the Controller's code is extracted, is to help us do the testing work.
Hopefully this article will help you master the correct use of MVC posture, and in the next section I'll share my view of MVVM.
The history of the deified MVVMMVVM
MVVM is shorthand for Model-view-viewmodel.
MVVM is a fairly new architecture relative to the history of MVC, and MVVM was first proposed by Microsoft's WPF and Silverlight architect John Gossman in 2005 and applied to Microsoft's software development. At that time, MVC had been put forward for more than 20 years, it can be seen how the age difference between the two.
In use, MVVM often uses two-way binding technology, so that when the Model changes, the ViewModel automatically updates, and when ViewModel changes, the View automatically changes. So, the MVVM pattern is sometimes called: Model-view-binder mode.
Specifically in IOS, you can use KVO or Notification technology to achieve this effect.
The Apotheosis of MVVM
In use, I've found a sense of "awe" about MVVM and the framework (like Reactivecocoa) derived from MVVM. This "awe" feeling is, to some extent, like God, which is largely manifested in my failure to hear any criticism of MVVM.
I feel that the first reason is that MVVM is not much popular, we are not familiar with new technology, and then do not dare to comment. In addition, the complexity of the Reactivecocoa itself, also makes many people feel that the technology is very difficult to understand, and thus aggravating the people's "awe" of it.
The role and problems of MVVM
MVVM can actually decouple the Model layer from the View layer in practice, but if you need to implement two-way binding in MVVM, you usually need to introduce more complex frameworks to implement.
In this respect, the author of MVVM John Gossman's criticism should be the most pertinent. John Gossman's criticism of MVVM has two main points:
1th: Data binding makes it difficult to debug a Bug. You see the interface is abnormal, it is possible that your View code has a Bug, it may be the Model code has a problem. Data binding makes a Bug in one location quickly passed to another location, and it becomes less easy to locate the original problem.
2nd: For an oversized project, data binding takes more memory.
In a sense, I think data binding makes MVVM complicated and difficult to use. However, this shortcoming is also considered by many people to be a virtue.
Reactivecocoa
Functional programming (functional programming) and responsive programming (React programming) are also two concepts that are currently very hot, and their combination makes it easy to implement data binding. So, in IOS programming, Reactivecocoa was born, its concept is very new, including:
- Functional programming (functional programming), the function becomes a class citizen, can have the same function as the object, for example, as a parameter passed, as a return value. You know how Cool it is to look at the many functional programming features that Swift language brings.
- Responsive programming (React programming), our event-based approach is weak, and is now based on the way input (called Signal in Reactivecocoa) is handled. Input can also be programmed by functional programming of various Combine or Filter, display a variety of flexible processing.
- Stateless (stateless), state is a function of the devil, stateless so that functions can be better tested.
- Non-modifiable (immutable), data are non-modifiable, making the software logic simple, can also be better tested.
Wow, all this is cool. When I saw it, I was frozen!
We should evaluate MVVM and Reactivecocoa objectively.
But, I suddenly thought, I just need a ViewModel, I can simply do a ViewModel factory class or Service class can be, why introduce so many frameworks? Is there really such a big problem with the existing MVC?
Until now, Reactivecocoa is still in the niche field both at home and abroad, and has not been widely accepted as the mainstream programming framework. Not only in the IOS language, but also in other languages, such as RxJava in Java, is not becoming mainstream.
I am here, not to say Reactivecocoa bad, nor to say that MVVM is not good, but to let everyone can have an objective understanding. Reactivecocoa and MVVM should not be deified, it is a novel programming framework that solves some of the problems of the old programming framework, but it also brings some new problems, and that's all there is to it. If you can't make good control of Reactivecocoa, it will also cause the Controller code is too complex, the code logic is not easy to maintain the problem.
Summarize
Some people are always chasing the technology, there is any new technology, regardless of 3,721 immediately use, the result is a variety of pits.
There are others who are always concerned about the technical risks of new technologies and are reluctant to learn. As a result, there are still people using the MRC to manually manage reference counts.
And I want to say that what we need to keep is a embracing change of heart, and a rational analytical attitude. In the face of new technology, not blindly, nor old-fashioned, all decision-making should be based on a careful analysis, so as to respond to technological changes.
Misunderstood MVC and the deified MVVM