The original link

At present, the most popular architecture for clients should be MVVM. However, after reading some articles, I found that most of them are theories without detailed explanation of specific architecture methods and practices. This blog is about my use in practical work.

The introduction

Mentioning MVVM, we have to first understand MVC: MVC mode (Model — view — Controller) is a software architecture mode in software engineering, which divides the software system into three basic parts: Model, view and controller. The MVC pattern, first proposed by Trygve Reenskaug in 1978 [1], is a software architecture invented by Xerox PARC for the program language Smalltalk in the 1980s. The PURPOSE of the MVC pattern is to achieve a dynamic programming that simplifies subsequent modification and extension of the program and makes it possible to reuse certain parts of the program. In addition, this mode simplifies the complexity of the program structure more intuitive. The software system entrusts the function of each basic part by separating its own basic part. Professionals can be grouped by their expertise:

  • Controller – Is responsible for forwarding requests and processing requests.
  • View – Interface designers design graphical interfaces.
  • Model – programmers write the functions that programs should have (implement algorithms and so on), database experts do data management and database design (can implement specific functions).

MVVM


MVVM is the abbreviation of Model-View-ViewModel. It was first proposed and used by Microsoft. It is a new architecture developed when MVP (Model-View-Presenter) mode is combined with WPF application mode. MVVM helps to separate the development of graphical user interfaces from the development of business logic or back-end logic (data models) through markup languages or GUI code. The viewmodel of MVVM is a value translator, which means that the viewmodel is responsible for exposing (transforming) data objects from the model for easy management and rendering of objects. In this regard, the viewmodel does more than the view and handles most of the view’s display logic. The view model implements the mediator pattern, organizing access to the back-end logic of the set of use cases supported by the view.

  • Model A model is either a domain model that represents real state content (object-oriented) or a data access layer that represents content (data-centric).
  • Just like in MVC and MVP patterns, a view is the structure, layout, and appearance (UI) that the user sees on the screen.
  • View model A view model is an abstraction of a view that exposes common properties and commands. MVVM has no MVC controller and no MVP presenter. Instead, it has a binder. In the view model, the binder communicates between the view and the data binder.
  • The binder declarative data and command bindings are implicit in the MVVM pattern. In the Microsoft solution heap, the binder is a markup language called XAML. The binder frees developers from having to write boilerplate logic to synchronize viewmodels and views. The emergence of declarative data binding technology was a key factor in implementing this pattern when implemented outside of Microsoft’s heap.

The advantages of MVVM

Solve the problem of controller overstaffing


In MVC it’s very easy to put some business logic, network requests, data IO in the Controller

Note that MVC controllers are not necessarily bloated, but “prone to become bloated.”

When we create a new project, Apple automatically generates a ViewController for us, and when we start to write code, we tend to write the logic directly into the Controller.

The MVVM architecture will require us to take any non-view logic out of the glass, and the code in the Controller will only allow operations on the View other than binding the viewModel. Because Controller to us is just a View.

Logical separation


As mentioned above, the business logic is siphoned off and placed in the viewModel so that the pile of business can be reused anywhere

In addition, our code will be much easier to test, avoiding the kind of overly long methods and heavy reliance on global state that can lead to hard-to-test problems in MVC.

View reuse (can have View separate viewModel)


In MVVM, the View only needs to interact with the ViewMode, will not receive other effects, so not only VM, M can be reused, the View can be reused, modify time is also more convenient.

disadvantages


Bugs and transfer


Since views and ViewModels are loosely coupled in MVVM, they need to be checked everywhere when testing for problems,

It could be in the VM or it could be in the View. Because VMS pass data, a bug can easily pass elsewhere, causing bigger problems.

And if something goes wrong in one place, the BUG is likely to spread to other logic, causing more serious problems.

The overhead of maintaining the Model, the viewModel, and the View, the controller is abstracted into the View.


The extra viewModel usage is not free, and can be slightly complicated to manage for a variety of reasons. On the other hand, if memory is not freed properly due to strong references or other reasons such as circular references, memory can explode, so make sure you use it in a way that has no side effects.

Method of use


This is just a general introduction, but let’s take a look at how to use it.

You can bridge the View to the viewModel using a delegate or a block, and in this case we’re going to use delegate, which I think is a little bit more intuitive and a little bit more explicit in the code.

Start by creating a project and selecting singleViewApplication, we’ll use the most common login function as an example

Create a protocol for the view to respond to when called by the viewModel


First of all, a name, call LoginViewModelDelegateProtocol

@protocol LoginViewModelDelegateProtocol <NSObject>

@end
Copy the code


Ok, so let’s think about what data the View sends to the VM and what data the VM needs.

For a simple login VM, we need to notify the View of the data and methods

  • Log in successfully
  • Error message
  • Button state changes (can be clicked)

So we can add methods to protocol

@protocol LoginViewModelDelegateProtocol <NSObject>

- (void)loginSuccess;
- (void)showTips:(NSString *)tip;
- (void)buttonEnable:(BOOL )enable;

@end
Copy the code


Create a protocol called by the View and responded to by the viewModel


Similarly, we just need to confirm the data that vm and V need to exchange.

  • The user name input box is a string
  • The character string of the password input box
  • Click login event
@protocol LoginViewModelInterfaceProtocol <NSObject>

- (void)inputUserName:(NSString *)uname;
- (void)inputPwd:(NSString *)pwd;
- (void)didTapLoginBUtton;

@end
Copy the code


Implementing proxy methods

So let’s create a new viewModel called LoginViewModel

LoginViewModel.h

#import <Foundation/Foundation.h>
#import "LoginViewModelDelegateProtocol.h"
#import "LoginViewModelInterfaceProtocol.h"

@interface LoginViewModel : NSObject<LoginViewModelInterfaceProtocol>

@property (nonatomic ,weak) id<LoginViewModelDelegateProtocol> delegate;

@end
Copy the code


LoginViewModel.m

#import "LoginViewModelDelegateProtocol.h"

@interface LoginViewModel(a)

@property (assign.nonatomic) BOOL unameValid;

@property (assign.nonatomic) BOOL pwdValid;

@end

@implementation LoginViewModel

- (void)inputUserName:(NSString *)uname {
    self.unameValid = uname.length>0;
    [self judgeAllValid];
}
- (void)inputPwd:(NSString *)pwd {
    self.pwdValid = pwd.length>0;
    [self judgeAllValid];
}
- (void)didTapLoginBUtton {
    // Some requests, ignore the network request, directly simulate the result
    [self.delegate loginSuccess];
}

- (void)judgeAllValid {
    BOOL v = [self isAllValid];
    [self.delegate buttonEnable:v];
}

- (BOOL)isAllValid {
    return self.unameValid && self.pwdValid;
}

@end
Copy the code


And then initialize it in controller and implement all the methods.

viewController.m

#import "viewController.h".@interface viewController()"LoginViewModelDelegateProtocol>
@property (nonatomic ,strong) LoginViewModel *vm;
@end

@implementation TDFSetPhoneNumController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    self.vm.delegate = self;
}

#pragma mark - VMDelegate

- (void)loginSuccess {
    [self.navigationController pushViewController:[SuccessVC new]] animated:true];
}
- (void)showTips:(NSString *)tip {
    [self showAlert:tip];
}
- (void)buttonEnable:(BOOL )enable {
    self.loginbutton.enable = enable;
}

#pragma mark - Getter

- (LoginViewModel *)vm {
    if(! _vm) { _vm = [LoginViewModel new]; }return _vm;
}
@end
Copy the code

You’re done


I wrote all the code by hand, and omitted some UIKit related layout. You should be able to easily complete the rest with your smart mind.

Matters needing attention

Here are a few things I think should be noted:

  • Regardless of what passes the value and response between VM and V, the data flows in one direction.
  • If the agent is weak, it will automatically set to nil when the memory is reclaimed.
  • All models and ViewModels should not contain any UIKit classes

conclusion

All in all, I think MVVM is very elegant and safe to use in our overall code division and application architecture,

But whatever the architecture is, it depends on how we use it, doesn’t it