OS Application architecture Talk (ii): View layer organization and invocation scenarios (middle)
Author Tian Wei-yu released on May 28, 2015 | Note: Archsummit Global Architects Summit (Beijing) December 2015 18-19th, learn more! discussion
- Share to: Weibo facebooktwitter Youdao Cloud Note email sharing
Read later
My list of reading
The iOS client application architecture looks simple, but there are many things to consider. The author of this article will be a series of articles to answer the questions in the iOS application architecture, this article is the second one, mainly on the view layer of the Organization and invocation scheme. Medium mainly discusses the application of MVC, MVCS, MVVM, Viper and other architectures in iOS development.
A whole bunch of ideas about MVC, MVVM, etc.
These are all relatively generic ideas, original aim or the three roles I mentioned in the opening: Data managers, data processors, data performers. These multifarious ideas are nothing more than the enactment of a norm that specifies how the three roles should be exchanged for data. But at the same time these are the most controversial topics, so I am here to put a few mainstream ideas to do a comb, when you do the view layer architecture, you can have a better reference.
Mvc
MVC (Model-view-controller) is the most old-style ideas, old to 4 people help book it into a model, wherein model is as a data manager, View as a data display, Controller as a data processor, The model and view are all deployed by the controller to the business requirements, so the controller also burdens a data flow provisioning function. While I was writing this article, I saw Infoq send this article, which mentions a pain point in mobile development: an understanding of the MVC Architecture Division. I was not able to attend the symposium, and I had no way to express my personal opinion, so I could only write here.
In the area of iOS development, how do we divide the MVC?
There are actually two problems in this:
- Why do we struggle with the problem of MVC partitioning in iOS development?
- In the field of iOS development, what is the right posture for partitioning?
Why do we struggle with the problem of MVC partitioning in iOS development?
On this, everyone's tangled point may not be the same, I do not know the discussion at the time of the views of everyone. But let me guess: Is it because Uiviewcontroller comes with a view and controls the entire life cycle of the view (Viewdidload,viewwillappear ... , and in common sense we all know that controller should not have such a close connection with view, so it leads to confusion about division? , I will give my opinion on this speculation.
In the area of server-side development, controller and view interact in a way that typically works like Yii:
/* ... Database fetch data ... Processing data ... * ///Here $this is controller $this->render ("plan", Array ( ' planlist ' = ' = $planList, ' plan_id ' = > $_get[' id '], ));
There is a clear distinction between the controller and the view, and after the controller has done his thing, he gives all the work on the view to the page rendering engine, and the controller does not do anything about the view, including the generation of the view, These are handled by the rendering engine. This is a difference, but in fact the concept of service-side view and native application view concept, the real difference is: from the concept of strict division, the server is actually no view, thanks to the HTTP protocol, The view we are talking about is just a string that describes the view (more essentially what should be called data), and the real view is the browser.
So the service side just generate a description of the view, as to the look of view, UI event monitoring and processing, is the browser responsible for generating and maintenance. But in the native side of the view, originally belong to the browser task also can not escape to do. So who's going to do the right thing? The answer Apple gives is: Uiviewcontroller.
Given that Apple has done a lot of hard work on this layer, it's not necessary for iOS engineers to do it themselves. Moreover, it puts all the functions on the UIView, and makes the UIView not only to display the UI, but also as an object of the container.
See here, do you understand? UIView's other identity is actually a container! Uiviewcontroller's own view, its main task is to act as a container. If all of its related names are changed to Viewcontainer, then the code will look like this:
-(void) viewcontainerdidload{ [Self.viewcontainer AddSubview:self.label]; [Self.viewcontainer AddSubview:self.tableView]; [Self.viewcontainer AddSubview:self.button]; [Self.viewcontainer AddSubview:self.textField];} ... ...
Just a change of name, is it a lot clearer now? To be more specific, the service-side MVC We normally think is divided into:
But in fact, the MVC divide for the entire process is this:
As can be seen from the figure, our service-side development in this concept, in fact, only involves the development of M and C, the browser as a view container, responsible for view display and event monitoring. So the MVC partition that corresponds to the iOS client is this:
The only difference is that the view container in the service side, is responsible for the browser, throughout the site process, the container placed in the browser is very reasonable. On the iOS client, the view container is responsible for the view in Uiviewcontroller, and I also think the Apple option is very correct and sensible.
Because the relationship between the browser and the server is very loose, and they belong to two different camps, the server will generate a description of the view and give it to the browser to show it, but once there are any events on the view, Basically it is rarely passed to the server (that is, the so-called controller) (it can also be: AJAX), all in the browser to do things out of the way, so in this case, the view container is suitable for the browser (V) side.
However, in the field of iOS development, although there is also the practice of allowing view to listen to events, it is very rare to pass events back to the controller, and then the controller is dispatched separately. So that's when the view container is placed in the controller. Controller can easily change the contents of the container because of the different events, such as loading failure, the container contents into the view of the failed page, no network, the container page into a network-free view and so on.
In the field of iOS development, what is the right posture for MVC partitioning?
The answer to this question is actually a part of it, so this question will be answered as a summary of the above question.
The things m should do:
- Provide data to Viewcontroller
- Providing an interface for Viewcontroller storage data
- Provides an abstract business base component for controller scheduling
c What should be done:
- Manage the life cycle of view container
- Responsible for generating all view instances and putting them into the view Container
- Listen to business-related events from view, and work with model to complete the business of the corresponding event.
V What to do:
- Respond to business-agnostic events, and thus trigger animations, click Feedback (if appropriate, try to do it in view), and so on.
- interface element expression
I answered these two questions by comparing it with the service-side MVC division, because I knew that a lot of iOS engineers had been transferred from the server before. I also like this, before entering the home, I also do the server development, in the process of learning iOS, I also once on the iOS domain MVC division problem has been puzzled, I doubt the point is the first point I guess. If someone asked me what I should do with MVC in iOS, I would answer like so.
MVCS
Apple itself is using this architectural approach, from the name can be seen, but also based on MVC derived from a set of architecture. Conceptually, the part that it splits is the model part, which is broken out into a store. This store is dedicated to data access. But from a practical point of view, it is the controller that is taken apart.
This is a thin model of a scheme, thin model is only used to express data, and then storage, data processing are handed out to do. The premise of Mvcs is that it assumes that you are a thin model, and that the data is stored and processed in the controller. So it corresponds to Mvcs, which is the controller that was split at the beginning. Because the controller does the data storage, it becomes very large, then the controller dedicated to access the data part of the extraction, to another object to do, this object is the store. After this adjustment, the whole structure becomes a real mvcs.
About fat model and thin model
When I was interviewing and chatting with others, I found that there were not many people who knew the concept of fat model and thin model. About two or three years ago, the foreign industry had a very heated discussion, the theme is Fat model, skinny controller. Now there is little discussion about this, but until today the fat model and the thin model which is better, the industry has not yet decided, so this is the current industry suspended and unresolved a controversy. I seldom see a domestic discussion of this information, so here I would like to add what is called fat model what is called thin model. And where their arguments came from.
What do you mean, fat model?
The FAT model contains some weak business logic. The goal of the FAT model is that, after the controller gets the data from the FAT model, it can apply the data directly to the view without extra action or with minimal manipulation. As an example:
Raw Data: timestamp:1234567fatmodel: @property (nonatomic, assign) cgfloat timestamp; -(NSString *) ymddatestring; 2015-04-20 15:16 -(NSString *) gapstring;//3 minutes ago, 1 hours ago, a day ago, 2015-3-13 12:34controller: self.dateLabel.text = [Fatmodel ymddatestring]; Self.gapLabel.text = [Fatmodel gapstring];
Converting timestamp into a string that is needed for a specific business, which is a business code, is a weak business. Fatmodel do these weak business, controller can become very skinny,controller only need to focus on the strong business code on the line. As we all know, the possibility of strong business change is much larger than weak business, weak business is relatively stable, so weak business into the model is no problem. On the other hand, the frequency of weak business repetition is greater than the strong business, the demand for reusability is higher, if this part of the business is written in the controller, similar code will be spilled everywhere, once the weak business has been modified (low frequency of weak business modification does not mean that there is no modification), this thing is a disaster. If you plug it into the model, you can change it in a lot of places and you can avoid this catastrophe.
However, its disadvantage is that the fat model is relatively difficult to transplant, although only contains weak business, but at least is also the business, migration is easy to pull out the carrot to take out the mud. On the other hand, the MVC architecture idea is more inclined to model is a layer, rather than an object, should not be a layer should be done to an object to do. Finally, software grows, and Fatmodel is likely to grow fat and ultimately difficult to maintain as the software grows.
What do you mean, thin model?
Thin model is only responsible for the expression of business data, all business, whether strong or weak are thrown to the controller. Thin model to achieve the purpose is to do everything possible to write fine-grained model, and then supporting a variety of helper classes or methods to do the weak business abstraction, strong business is still handed to the controller. As an example:
Raw data:{ "name": "Casa", "sex": "Male",}slimmodel: @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *sex; Helper: #define Male 1; #define Female 0; + (BOOL) sexwithstring: (NSString *) sex; Controller: if ([Helper sexWithString:SlimModel.sex] = = Male) { ... }
Since Slimmodel is completely unrelated to the business, its data can be handed to any helper or other object that can handle its data to complete the business. When the code is migrated, the independence is very strong, and it is rare to get the carrot out of the mud. In addition, because Slimmodel is only data expression, maintenance of it is basically 0 cost, the software expands so badly, Slimmodel is not big to go.
The downside is that the helper is not very good, and there is an article criticizing this. In addition, because the model operation will appear in various places, slimmodel to some extent contrary to dry (Don ' t Repeat yourself) ideas, controller still inevitably to some extent the code expansion.
My attitude? Well, I'll say it in this section of the heart of this door.
Said back, Mvcs is based on a thin model of an architectural approach, the original model to do a lot of things in the data storage code is abstracted into a store, to a certain extent, reduce the controller pressure.
MVVM
MVVM discussed very much in the industry last year, both at home and abroad, especially after the Reactivecocoa of the library, ViewModel and view's signaling mechanism has finally had a relatively elegant implementation under iOS. MVVM is essentially an idea derived from MVC, and the problem that MVVM focuses on is to minimize the controller's task as much as possible. Regardless of MVVM or mvcs, their consensus is that the controller will grow with the software, it is very difficult to maintain difficult to test. But the premise of the two kinds of architecture is different, Mvcs is that the controller did a part of the model, to take it out into STORE,MVVM is that the controller did too much data processing things, So MVVM frees up the task of data processing from the controller, so that the controller only needs to focus on the work of data provisioning, and ViewModel is responsible for data processing and changing the view response ViewModel by notification mechanism.
MVVM is based on the idea of a fat model architecture, and then splits two parts in the FAT model: model and ViewModel. I would like to make an additional explanation about this point: the FAT model does the job of offloading the controller first, and then because the model becomes fat, and then the ViewModel on this basis, with the industry generally understand that MVVM is essentially for controller to lighten the argument that it is not contradictory, Because the FAT model does the thing also for controller burden.
In addition, I said that MVVM freed the task of data processing from the controller, and it was not contradictory to split the fat model with MVVM. To liberate the controller, first you have to have a fat model and then split the FAT model into model and ViewModel.
So what exactly is MVVM supposed to accomplish?
This is most likely the problem that most people struggle with, and I intend to try to answer this question here with my personal experience, and welcome the exchange.
Most of the MVVM architectures in iOS use Reactivecocoa, but are iOS apps using Reactivecocoa based on the MVVM architecture? Of course not, I think a lot of people have this misunderstanding, some of the people I interviewed mentioned that Reactivecocoa also referred to MVVM, but their understanding of this is so superficial that I can not help laughing. Well, I'll cite an example of not using REACTIVECOCOA in the network layer architecture, and now I feel a little early.
The key to MVVM is to have a view model! And not Reactivecocoa.
Note: MVVM to have ViewModel, as well as Reactivecocoa to bring the signal notification effect, in Reactivecocoa is the RAC and other related macros to achieve. In addition, the use of Reactivecocoa can be more elegant to implement the MVVM pattern, because there is a RAC and other related macros exist. Just like its name. reactive--reactive, which is also an important aspect of the C and MVP P of the VM and MVC that distinguishes MVVM.
What do viewmodel do? is to turn RawData into a model for objects that can be used directly by view. As an example:
Raw Data: { ( (123, 456), (234, 567), ( 345, 678) ) }
Here the rawdata we assume is latitude and longitude, the number I write casually don't care too much. Then you have a module that is a map module that transforms all the latitude and longitude groups into mkannotation or its derived classes are weak for the controller, (remember, the FAT model is used to do weak business), So we use ViewModel directly to transform it into a mkannotation nsarray, to the controller after the controller can be used directly.
Well, this is what ViewModel to do, is not it easy to see the superiority?
There is also a map module, where I designed an object called reformer (in fact, ViewModel), dedicated to doing this thing. So where is the superiority of doing so?
Settlement of the three major business: rent, housing, new houses. The three business counterparts in the mobile development team have three API development teams, they are fragmented, which results in a result: Three API team feedback to the mobile client data content is consistent, but the data format is inconsistent, that is, the same value corresponding to the key is inconsistent. But the viewcontroller of the show map can't write three, so there must be an API data compatibility logic, this logic I put in reformer inside to do, so the business process becomes this:
As a result, the complex mkannotation assembly logic is split out of the controller and the controller can display the data returned directly from the reformer. Apimanager belongs to the Model,reformer and belongs to ViewModel. Specific about reformer I will put in the network layer architecture to explain in detail. Reformer at this time played the role of ViewModel can be very good to the controller burden, at the same time, maintenance costs are greatly reduced, after reformer output is always mkannotation,controller can be taken directly to use.
Then another point, there is a business need to take the nearby listings, Map API request is able to hold the demand, then other places do not change, in the Fetchdatawithreformer when the change of a reformer can be, All the other things were given to reformer.
So what role should Reactivecocoa play?
Not Reactivecocoa can mvvm, with Reactivecocoa can better embody the essence of MVVM. The example I mentioned above is only the data from the API to the view direction, the operation of the view will also produce "data", but here the "data" is more in the expression of the user's operation, such as the input of what content, then the data is text, choose which cell, Then the data is Indexpath. So in the direction of data from view to API or controller, that is where Reactivecocoa play.
We know that ViewModel is essentially the model layer (because it is part of the FAT model), so view is not suitable for holding viewmodel directly, so what happens when the view generates data? Throw the signal to ViewModel, who throws it? Reactivecocoa.
The first purpose of using Reactivecocoa in MVVM is to say that view is not suitable for holding viewmodel directly. The second goal is that ViewModel may not only serve a particular view, but using a looser binding relationship can reduce the coupling between viewmodel and view.
So what role does the controller play in MVVM?
Most of the data at home and abroad describe MVVM in this way: View <-> ViewModel <-> Model, causing MVVM to not need controller illusion, Now it seems that the industry is starting to show that MVVM does not require a controller. 's voice. In fact, MVVM must be involved in the controller, although MVVM to a certain extent weakened the controller's sense of existence, and to the controller to lighten the weight (which is the main purpose of MVVM). However, this does not mean that the relationship between CONTROLLER,MMVC and MVVM is not required in MVVM:
(Source: http://www.sprynthesis.com/2014/12/06/reactivecocoa-mvvm-introduction/)
View <-> C <-> ViewModel <-> Model, so after using MVVM, it is not appropriate to say that the controller is not needed. In strict terms, MVVM is actually a MVCVM. As you can tell, one of the main things that the controller clamps between view and ViewModel is to bind the view and the ViewModel. Logically, the controller knows which View,controller should be shown and which viewmodel to use, whereas the view and ViewModel are not known to each other, so the controller is responsible for controlling their binding relationships. So called controller/controller is the reason.
The front pulls so much, in fact, is a sentence: On the basis of MVC, C, a viewmodel specifically responsible for data processing, is MVVM. Then, in order to have a loosely binding relationship between the view and the ViewModel, we use Reactivecocoa, because Apple itself does not provide a binding method that is better suited to this situation. The iOS realm kvo,notification,block,delegate and target-action can be used to do data communication, so as to achieve the binding, but not as Reactivecocoa provides the elegance of racsignal, Without Reactivecocoa, a binding relationship might not be as loose as it would be, but it doesn't affect it or MVVM.
In the real iOS app architecture, MVVM should appear in the iOS app architecture for most startups or old company new apps, and as I know ePRO pays for an iOS app that uses the MVVM architecture as a whole, they pull out an action layer to install all kinds of viewmodel, Also belong to a relatively reasonable structure.
So in MVVM, the controller is responsible for the binding between view and ViewModel, and on the other hand, the normal UI logic processing.
VIPER
VIPER (view,interactor,presenter,entity,routing). Viper I didn't actually use it, I saw it in the 13th issue of Objc.io.
Whenever there is a new architecture or a new architecture that I'm not familiar with, one thing I can be sure of is that it must be the part of the MVC that has been disassembled (the theoretical basis for this judgment in the first article I have already said). The fact is that Viper really demolished a lot, except that the view was not demolished, the others were dismantled.
The two articles I mentioned are very detailed about Viper, and I understand them at a glance. But specifically in the use of Viper when there will be a pit or what controversy I am not very clear, hard to write this section of the words I can only rely on yy, so I think or forget. If you have any readers who use the Viper architecture in the actual app or are interested in Viper, you can comment on the area and we'll talk about it.
PostScript language
In order to better export quality content to readers, INFOQ will select excellent articles from home and abroad and post them to the website after being collated and reviewed. The author of this article is Tian Wei-yu, the original link to Casa Taloyum. This article has been reproduced by the original author authorized Infoq Chinese station.
Thank Xuchuan for the review of this article.
OS Application architecture Talk (ii): View layer organization and invocation scenarios (middle)