Go to Introduction MVVM

Source: Internet
Author: User

Introducing MVVM

This article translated from: http://www.objc.io/issue-13/mvvm.html

Original Ash Furrow

Translator: @nixzhu

I found my first IOS development job in 500px in 2011. Although I have been in the university for several years iOS outsourcing development, but this is my real iOS development work. I was recruited to implement an IPad app that has a beautiful design and is the only IOS developer. In just seven weeks, we released 1.0 and continued iterations, adding more features, but in essence, the codebase became more complex.

Sometimes I feel like I don't know what to do. I know my design patterns-just like any good programmer-but I'm too close to the product I'm working on to objectively measure the effectiveness of my architectural decisions. It brought me another developer, and I realized we were in trouble.

Never heard of MVC? Some call it a Massive View controller (heavyweight view controllers). That's how we felt back then. I'm not going to introduce embarrassing details, but it's enough to show that if I had to do it again, I would definitely make a different decision.

I'll modify a key architecture and bring it into the various applications I've been developing since then, even replacing Model-view-controller with a schema called Model-view-viewmodel.

So, what exactly is MVVM? Instead of focusing on explaining the origins of MVVM, let's look at how a typical IOS is built and learn about MVVM from there:

What we see is a typical MVC setting. The Model renders the data, the view renders the user interface, and the view Controller adjusts the interaction between the two. cool!

Think about it a little bit, although the view and view controllers are technically different components, they are almost always hand in hand and paired. When did you see a view that could be paired with a different view Controller? Or vice versa? So, why not formalize their connections?

This is a more accurate description of the MVC code you might have written. But it doesn't do much to solve the growing weight-level view controller in IOS apps. In a typical MVC application, Many logic is placed in the View Controller. Some of them do belong to the view Controller, but more so-called "presentation logic", in the terms of MVVM-the thing that transforms data from the Model into what the view can render, such as a NSDateconverted to a formatted one NSString .

There is something missing in our diagram. Something that allows us to place all the representations of logic. We're going to call it "View Model"--it's between View/controller and model:

It looks much better! This diagram accurately describes what MVVM is: An enhanced version of MVC, where we formally connect the view and controller, and move the representation logic out of the controller and into a new object, the view Model. MVVM sounds complicated, but it's essentially a well-optimized MVC architecture, and MVC is familiar to you already.

Now we know what MVVM is, but why would someone want to use it? The motivation to use MVVM on IOS, for me anyway, is that it can reduce the complexity of the View Controller and make the presentation logic easier to test. With some examples, we will see how it achieves these goals.

Here are three key points that I would like you to take from this article:

    • MVVM is compatible with the MVC architecture you are using today.
    • MVVM makes your app more testable.
    • MVVM works best with a binding mechanism.

As we've seen before, MVVM is basically an improved version of MVC, so it's easy to see how it can be integrated into existing applications that use a typical MVC architecture. Let's look at a simple Person Model and the corresponding View Controller:

@interfacePerson:Nsobject-(Instancetype)Initwithsalutation:(NSString *)SalutationFirstName:(NSString *)firstname lastname:(NSString *) lastname birthdate:(NSDate *) Span class= "Pl-smi" >birthdate;  @property (nonatomic, readonly)  NSString *salutation;  @property (nonatomic, readonly)  NSString *firstname;  @property (nonatomic, readonly)  NSString *lastname;  @property (nonatomic, readonly)  NSDate *birthdate;  @end               

cool! Now let's assume that there is one PersonViewController , in viewDidLoad which only a model few labels can be set based on its properties.

- (void) Viewdidload {[SuperViewdidload];if (self.Model.Salutation.Length >0) {self.Namelabel.Text = [NSStringstringWithFormat:@"%@%@%@",Self.model.salutation,Self.model.firstName,self.model.lastname]; } else {self. Namelabel. text = [nsstring stringwithformat: @ "%@ %@self.model.firstname, self.model.lastname]; } nsdateformatter *dateformatter = [[nsdateformatter  Alloc] init]; [Dateformatter setdateformat:@ "EEEE MMMM D, Yyyybirthdatelabel. text = [dateformatter stringfromdate:model.birthdate];}     

It's all straightforward, vanilla MVC. Now let's see how we can use a View Model to enhance it.

nsobject-(instancetype)initwithperson:(person *) person;  @property (readonly) person *person;  @property (nsstring *nametext;  @property (nsstring *birthdatetext;  @end          

The implementation of our View Model is probably as follows:

@implementationpersonviewmodel-(Instancetype)Initwithperson:(person *)person {self = [SuperINIT];if (!self)ReturnNil _person = person;if (person.Salutation.Length >0) {_nametext = [NSStringstringWithFormat:@"%@%@%@",Self.person.salutation,self.person.firstname, self.person.lastname];} else {_nametext = [nsstring stringwithformat:@ "%@ %@"  Self.person.firstName, self.person.lastname]; } nsdateformatter *dateformatter = [[nsdateformatter  Alloc] init]; [Dateformatter setdateformat:@ "EEEE MMMM D, Yyyystringfromdate:person.birthdate]; return self;}  @end               

cool! We have viewDidLoad put the representation logic in our View Model. At this point, our new viewDidLoad will be very light weight:

-(void) viewdidload {    [viewdidload];    Self. Namelabel. text = self. ViewModel. nametext; self. Birthdatelabel. text = self. ViewModel. Birthdatetext;}         

So, as you can see, there's not much change in our MVC architecture. Or the same code, just moved the location. It is compatible with MVC, resulting in a lighter View Controllers.

Can be tested, eh? How is it? Well, View controllers are famous for their hard-to-test, because they do too many things. In MVVM, we try to move the code as much as possible into the View Model. It's much easier to test the view Controller because they don't do a lot of things, and the view Model is very easy to test. Let's take a look at:

Specbegin (person) nsstring *salutation = @ "Dr.";NSString *firstname =@ "First";NSString *lastname =@ "Last";NSDate *birthdate = [NSDatedateWithTimeIntervalSince1970:0];It (@ "should use the salutation available.", ^{person *person = [[PersonAllocInitwithsalutation:salutationFirstname:firstnameLastname:lastnameBirthdate:birthdate]; Personviewmodel *viewmodel = [[PersonviewmodelAllocInitwithperson:person];Expect (ViewModel.Nametext).To.Equal@ "Dr. First Last"); });It (@ "should not the use of an unavailable salutation.", ^{person *person = [[PersonAllocInitwithsalutation:NilFirstname:firstnameLastname:lastnameBirthdate:birthdate]; Personviewmodel *viewmodel = [[PersonviewmodelAllocInitwithperson:person];Expect (ViewModel.Nametext).To.equal (@ "first Lastit (@ "should use the correct date format. ", ^{person *person = [[Person alloc] initwithsalutation:nil firstname:firstname lastname:lastname  Birthdate:birthdate]; Personviewmodel *viewmodel = [[Personviewmodel alloc] initWithPerson:person ]; expect (Viewmodel. Birthdatetext). to. equal (@ "Thursday January 1, 1970 "); }); Specend                

If we do not move this logic into the view Model, we will have to instantiate a complete view Controller and accompany the view, then compare the values of the lable in our view. This does not just become an indirect layer of trouble, but it also represents a very vulnerable test. We now have the freedom to modify the view hierarchy as we wish without worrying about destroying our unit tests. The benefits of using MVVM for testing are clear, even for this simple example, and in the case of more complex presentation logic, this benefit is even more pronounced.

Note that in this simple example, the model is immutable, so we can specify the properties of our View Model only at initialization time. For variable model, we also need to use some binding mechanisms so that the View model can update its properties when the model changes behind it. Also, once the model on the view model has changed, the view's properties need to be updated. The model changes should cascade down through the view Model into view.

On OS X, we can use COCOA bindings, but we don't have such a good configuration available on IOS. We thought of KVO (Key-value observation), and it did a great job. However, a large template is required for a simple binding, not to mention that there are many properties that need to be bound. As an alternative, I personally prefer to use Reactivecocoa, but MVVM does not force us to use Reactivecocoa. MVVM is a great model, independent of itself, and is better done when there is a good binding framework.

We covered a lot of things: derive mvvm from normal MVC, see how they are compatible paradigms, watch MVVM from a testable example, and see that MVVM works better with a paired binding mechanism. If you are interested in learning more about MVVM, you can look at this blog, which explains the benefits of MVVM in more detail, or how we have achieved great success with MVVM in recent projects. I also have a fully tested, MVVM-based application called C-41, which is open source. Go and see if you have any questions, please let me know.

To introduce MVVM

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.