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

  • Controller –> Is responsible for forwarding requests and processing requests.
  • View –> Interface designer for graphic interface design.
  • The programmer writes the function that the program should have (realizes the algorithm and so on), the database expert carries on the data management and the database design (can realize the concrete function).


The above is from Wikipedia, the following is a bit of artificial description (simple to understand)~

  • Model layer: data processing layer, including network request and data processing
  • View layer: The interface visible on all apps
  • Controller layer: An intermediary between the Model and View layers, displaying Model data on the View
  • Purpose: Low coupling, reusable


Controlller is a UIViewController in iOS, so many people write their views in controllers, as shown below:

@implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; //setupUI //1.createView UIView *view = [[UIView alloc]init]; view.frame = CGRectMake(100, 100, 100, 100); view.backgroundColor = [UIColor orangeColor]; [self.view addSubview:view]; //2.createButton UIButton *btn = [UIButton buttonWithType:UIButtonTypeInfoDark]; btn.center = self.view.center; [self.view addSubview:btn]; / / 3... }Copy the code

I just got this notationiOSHere are the benefits of writing this way, and why beginners write this way:

  1. Buttons, for example, can be directly in the current controlleradd target:Add click events, click methods can be called within the current controller, no need to set up proxies and so on;
  2. For example, if you want to find an interface, just go to the corresponding interfacecontrollerJust becauseViewWritten in the bookControllerInside, you don’t have to look anywhere else, it’s here;
  3. For example, if you have a View that has an image in it, and the image is dependent on a network resource, the benefit of writing this way can be directly changedViewControllerIn can get the resource, do not need to pass the value

Shortcomings!!!!! :

  • Lead toControllerEspecially bloated, there is a lot of code, a complex view, the amount of code may be more than 1000 lines, difficult to maintain
  • Written in the bookControllerCannot be reused unless you copy the current VC in VC2ViewThe code of
  • Very low!! People who understand architecture look down on youMVC, it isMCArchitecture, you may need to prove yourself to the mic (-. -)


How to say goodbyeMCMode, really go toMVC?

  1. You start by brainwashing yourself,iOStheControllernotUIViewController“, but ordinaryController, there is noView. (A crucial step)
  2. Modular division, each module corresponding to its own View, such as Demo2 module, View layer inside aDemo2ViewWrite interface elements to the View

Knowledge 1: How to Pass values (Parameters)

//View
+ (instancetype)viewWithTitleStr:(NSString *)titleStr{
    
    //docreateView //... } //Controller @implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; /*setupUI*/ /1. CreateView - Pass the argument to the function 'View' as an external argument DemoView * View = [DemoView viewWithTitleStr:@"I'm a parameter."];
    [self.view addSubview:view];
}
Copy the code

Knowledge 2: How are control click events called back to controllers

//View
@implementation DemoView

- (instancetype)initWithTitleStr:(NSString *)titleStr{
    if (self = [super init]) {
        
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeInfoDark];
        [self addSubview:btn];
        [btn addTarget:self action:@selector(p_clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    }
    returnself; } - (void)p_clickBtn (UIButton *)sender{// Delegate respondsToSelector:@selector(clickBtn:)]? [_delegate clickBtn:sender] : nil; } //Controller @implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; //setupUI //1.createView DemoView *view = [DemoView viewWithTitleStr:@"I'm a parameter."];
    view.delegate = self;
    [self.view addSubview:view];
}

#pragma mark - privateDelegate- (void)clickBtn:(UIButton *)sender{//View layer button click callback ~}Copy the code


iOS MVC

@implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; //loadDatas [[AFHTTPSessionManager manager]GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// Refresh tableView _datas = responseObject;  } failure:nil]; }Copy the code

I just got this notationiOSFirst of all, the advantages of writing this way, and why beginners write this way:

  1. Simple, network request, directly in the current controller refreshTableViewThe data source
  2. For example, if you want to find a network request for a particular interface, go directly to the corresponding interfacecontrollerOk, because the data request is written inControllerInside, you don’t have to look anywhere else, it’s here;
  3. For example, the current network request interface requires external parameters, such as those of the previous interfaceuuidThe advantage of writing this way is that the current request can be directly placed inControllerIn can get the resource, do not need to pass the value

Shortcomings!!!!! :

  • Again lead toControllerEspecially bloated, there is a lot of code, if the current controller needs multiple requests, the amount of code may be more than 1000 lines, difficult to maintain
  • Written in the bookControllerCannot be reused unless you copy the current VC in VC2Network requestThe code of
  • If some interfaces have dependency requirements, interface 1 requests and then request interface 2, nested together, the degree of hot eyes almost cured my years of myopia
  • Very low!! People who understand architecture look down on youMVCIf you still use the one aboveViewWritten in the bookControllerCongratulations to you, the ultimate dafaThe Controller architectureWhat does it take to get it doneModel && View


How to say goodbyeVCMode, really go toMVC?

  1. Don’t brainwash yourself. Give yourself a kick in the ass. It’siOStheControllerevenUIViewControllerNeither did IMOh, noModel. (A crucial step)
  2. Modular division, each module corresponds to its own Model, such as Demo2 module, View layer has aDemo2Model, writes the network request && data processing toModelIn the

Knowledge 1: How to Pass values (Parameters)

@implementation DemoModel + (NSArray *)fetchDatasWithUUid:(NSString *)uuid{//Model sends network request NSDictionary *parameters = @{@"uuid":uuid} [[AFHTTPSessionManager manager]GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// This is an asynchronous requestreturn array
        } failure:nil];
    
}
Copy the code

Knowledge 2: How to call back (network request is asynchronous request) – by Block

//Model @implementation DemoModel + (void)fetchDatasWithUUid:(NSString *)uuid success:(successBlock)block{//Model sends a network request  NSDictionary *parameters = @{@"uuid":uuid} [[AFHTTPSessionManager manager]GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// Through block async callback ~ block(responseObject);} failure:nil]; } //Controller @implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; //loadDatas [DemoModel fetchDatasWithUUid:_uuid success:^(NSArray *array) { _datas = array; [_tableView reloadDatas]; }]; }Copy the code

The basic MVC is explained, in fact, is essentially to relieve the Controller, the Controller should not be in charge of him do not let him know, after the above basic MVC operation advantages:

  • MVC architecture is distinct, in the same module, ifviewThere is a problem, find the moduleViewAll right, and the same goes for everything else,ControllerThe code is greatly reduced and responsibleViewThe proxy event of
  • You can reuse, such as a product list of data, the home page also want to use, product page also want to use, directly in its corresponding respectivelyVC1 && VC2Call a function[ProductModel fetchDatas]You don’t have to write it multiple times. Same thing with View reuse
  • Structure is clear, easy to maintain, expansion is based on this expansion, clean and concise code.

MVC with inheritance, improve efficiency

  • The usual way to do it, you pick oneThe base classCome out,inheritanceA subclass can have a method of its parent class
Typedef void (^MNsuccessBlock)(NSArray *array); + (void)fetchDatasSuccessBlock:(MNsuccessBlock)block; + (void)fetchDatasSuccessBlock:(MNsuccessBlock)block failureBlock:(MNfailureBlock)failure;Copy the code

If, if you pull out a base class of the data model, such as MNBaseDatas here, like DemoModel, you don’t need to declare it

@interface DemoModel : //typedef void (^successBlock)(NSArray *array); //typedef void (^successBlock)(NSArray *array); //+ (void)fetchDatasSuccessBlock:(MNsuccessBlock)block; @end //Controller @implementation DemoViewController - (void)viewDidLoad { [super viewDidLoad]; //loadDatas -demomodel not declared -fetchdatasSuccessBlock [DemoModel fetchDatasSuccessBlock:^(NSArray *array) {_datas = array; [_tableView reloadDatas];}]; }Copy the code

If the parent class does not have a method or attribute, in the subclass of the line, will not affect the parent class code, the parent class is generally also put public, commonly used methods (or attributes), if it is special, directly in the subclass of the new can be added, do not need to add to the parent class ~


Controllers can also use inheritance, which can reduce a lot of redundant code

@interface MNBaseViewController: UIViewController @property (nonatomic, weak)UITableView *tableView; @property (nonatomic, copy)NSArray *datas; - (void)setupUI; - (void)loadDatas; @ the end / / MNBaseViewController. M file @ interface MNBaseViewController () < UITableViewDelegate, UITableViewDataSource >#pragma mark - setupUI- (void)setupUI{self UITableView *tableView = [[UITableView alloc]init]; tableView.frame = Frame(0, DefaultNaviHeight, ScreenW, ScreenH - DefaultNaviHeight); tableView.delegate = self; tableView.dataSource = self; }Copy the code
  • According to our package, basically all controllers need to set up the interfacesetupUITo get the dataloadDatas, so draw the two functions into the base classMNBaseViewController
  • becauseiOS,tableViewIt’s probably one of the most common controls, and basically most interfaces use it to display data, sotableViewAlso draws into the base class when the property is advertised
  • There aretableViewI can’t get away from the data source,datasSimilarly, base classes are drawn
  • Also, setMNBaseViewControllerBecome atableViewdelegateanddataSourceAll subclasses need not be declared
  • Use it if you need ittableViewA [super setUI] can own thistableView, no need to create

In this way, all UIViewControllers that inherit from MNBaseViewController can have functions and methods like the above (can be expanded as needed).


Advanced MNBaseViewController

/ / inherited from ` MNBaseViewController ` / * data structure is - @ [], no section tableVIew * / @ interface MNBaseControllerTypeNoSection: MNBaseViewController @ the end / * data structure is - @ @ []], a section of the tableVIew * / @ interface MNBaseControllerTypeHadSection: MNBaseViewController @endCopy the code
/ / implementation / * * / * * no section tableVIew @ implementation MNBaseControllerTypeNoSection - (NSInteger) tableVIew: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section {// no section, return the data source count directlyreturnself.datas.count; } @ the end / * * / * * a section tableVIew @ implementation MNBaseControllerTypeHadSection -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{return self.datas.count;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [self.datas[section] count];
}

@end

Copy the code

As the two base class MNBaseControllerTypeHadSection MNBaseControllerTypeNoSection, according to the needs of our own data source, choose to inherit from which class, They have all the properties of their parent class MNBaseViewController, their subclasses, You don’t have to write things like -(NSInteger)tableView:(UITableView *)tableView NumberOfRowsInSection: (NSInteger) section, – (NSInteger) numberOfSectionsInTableView tableView: (UITableView *) methods, such as Greatly reduce redundant code ~

As shown in the figure, I randomly selected several interfaces, probably some people have done similar interface, through a reasonable architecture, most of the controller code may be only 100 lines, details can be seen in Demo~



conclusion

For architecture, different people have different opinions, everyone has a suit for their own, not to say how low MVC, MVVM cast MVC technology 10086 street, mainly according to the project, according to their own use slowly advanced.

Below is a Demo I recently spent several hours drawing out. Of course, in the actual development, there may be more code for Controller, because some codes of click events are wrapped and called, and it is easy for viewers to go astray when I put them in, so click events are almost noted out. However, with this in mind, I actually recently wrote a multi-filter bag sliding multi-controller interface. The interface is relatively complex and the controller code is only 200 lines, which is generally clean.

Actually, TableView can also be stripped out, not in the Controller, and I had a Demo that did that, but it didn’t have to be that way, and I felt like I was just gilding the lily a little bit, because in my architecture, a lot of TableView methods are actually in the base class Controller, So there’s not a lot of tableView code in the Controller.

MVC architecture practice -Demo


Welcome to star ~