笔者在暑假的学习中完成了一些小项目,这些小项目中间有时候出现了一个小bug都要寻找很久,而且会导致所有整个项目无法运行,这时候就更体现了我们一个优秀的项目需要满足的几个要求:高内聚,低耦合。 代码均摊,易于扩展,具有易用性。
我们创建一个控件,设置这个控件的样子,设置这个控件的交互方法,展示这个控件,都需要一定的代码量,控件少的时候还好,看得过去,但是控件一多,像下面这个App 的界面,各种控件就多起来了,这个时候如果还把他们都堆在一个ViewController 里面就不合适了,要改bug,要添加控件就会变得非常麻烦。
这时候我们就会发现我们的一个ViewController的代码会非常臃肿,修改代码也不方便。这时候我们就出现了一个MVC架构来解决这种代码臃肿的情况,尽可能的降低耦合度,实现一个代码均摊的效果。
MVC是Model-VIew-Controller,就是模型-视图-控制器,MVC把软件系统分为三个部分:Model,View,Controller。其就是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
通俗来说,就是你的程序是什么,就是你的程序将要实现的功能,或者是它所能干的事情。也就是微信消息列表里的人名字,信息内容,头像,是否屏蔽该人的消息等等数据,可以认为,Model 里面装满了这个程序的各种数据,它负责处理数据、以及处理部分的业务逻辑。
通俗来说,在屏幕上你所看到的,这里有一个UITableView,TableView 里面有UILabel,UIImageView,你在屏幕上看到的组件,都可以归类为View。
它将数据从Model 层传送到View 层并展示出来,同时将View 层的交互传到Model 层以改变数据。大部分的逻辑操作(点击Button就是一种逻辑)都应该交由VC完成。
苹果官方的图片
斯坦福大学公开课的图片
这张图展示了MVC架构中各个部分的关系,下面来介绍一下各个部分之间的联系:
根据学长学姐的博客,我发现大部分学长都还是写了一个登陆注册的小demo来练习这个模式。
首先我们先要对相关的文件进行一个分类,根据不同的界面,划分成为不同MVC的模块
这里我们把登陆界面和注册界面分成两个部分,然后就是对于每一个层该怎么编写代码的问题了,这里以登陆界面的MVC来作为了示例
LandModel这里主要就是一个账号密码的作用。
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LandModel : NSObject
@property (nonatomic, strong) NSMutableDictionary* Dictionary;
#import "LandModel.h"
@implementation LandModel
-(instancetype)init{ // 重写一下初始化的函数
if (self = [super init]) {
self.Dictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
@end
这个数据层你可以发现他仅仅包含了我们这里的一个账号密码的内容,然后重写一下初始化的函数。这里就完成了有关数据层的内容。
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface LandView : UIView
@property (nonatomic, strong) UITextField* nameTextField;
@property (nonatomic, strong) UITextField* passwordTextField;
@property (nonatomic, strong) UIButton* registerButton;
@property (nonatomic, strong) UIButton* landButton;
@end
NS_ASSUME_NONNULL_END
#import "LandView.h"
#define MAS_SHORTHAND
#define MAS_SHORTHAND_GLOBALS
#import "Masonry.h"
@implementation LandView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
self.backgroundColor = UIColor.redColor;
self.nameTextField = [[UITextField alloc] init];
self.nameTextField.backgroundColor = UIColor.whiteColor;
self.passwordTextField = [[UITextField alloc] init];
self.passwordTextField.backgroundColor = UIColor.whiteColor;
self.passwordTextField.secureTextEntry = YES;
self.nameTextField.placeholder = @"请输入用户名";
self.passwordTextField.placeholder = @"请输入密码";
self.registerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.registerButton.titleLabel.text = @"注册";
self.registerButton.backgroundColor = UIColor.whiteColor;
[self.registerButton setTitle:@"注册" forState:UIControlStateNormal];
self.landButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.landButton setTitle:@"登陆" forState:UIControlStateNormal];
//self.landButton.titleLabel.text = @"登陆";
self.landButton.backgroundColor = UIColor.whiteColor;
[self addSubview:self.registerButton];
[self addSubview:self.nameTextField];
[self addSubview:self.passwordTextField];
[self addSubview:self.landButton];
[self.nameTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(CGSizeMake(210, 40));
make.top.equalTo(200);
make.left.equalTo(100);
}];
[self.passwordTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(CGSizeMake(210, 40));
make.top.equalTo(self.nameTextField).offset(60);
make.left.equalTo(self.nameTextField.left);
}];
[self.registerButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(CGSizeMake(100, 40));
make.top.equalTo(self.passwordTextField).offset(60);
make.left.equalTo(self.nameTextField.left).offset(5);
}];
[self.landButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(CGSizeMake(100, 40));
make.top.equalTo(self.passwordTextField).offset(60);
make.right.equalTo(self.nameTextField.right).offset(5);
}];
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
在这个部分我们需要重写我们的initWithFrame
这个函数,**如果在子类中重载initWithFrame方法,必须先调用父类的initWithFrame方法。在对自定义的UIView子类进行初始化操作。**然后我们在这个子类中重新完成相关内容。
这个层用来处理有关交互的逻辑部分
#import <UIKit/UIKit.h>
#import "RegisetController.h"
#import "LandModel.h"
#import "LandView.h"
NS_ASSUME_NONNULL_BEGIN
@interface LandController : UIViewController<comfirmDelegate>
@property (nonatomic, strong) LandModel *myModel;
@property (nonatomic, strong) LandView *myView;
@end
NS_ASSUME_NONNULL_END
#import "LandController.h"
#import "RegisetController.h"
@interface LandController ()
@end
@implementation LandController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.redColor;
self.myView = [[LandView alloc] initWithFrame:self.view.bounds];
self.myModel = [[LandModel alloc] init];
[self.view addSubview:self.myView];
[self.myView.registerButton addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];
[self.myView.landButton addTarget:self action:@selector(press1) forControlEvents:UIControlEventTouchUpInside];
// Do any additional setup after loading the view.
}
-(void)press1 {
if ([self.myModel.Dictionary[self.myView.nameTextField.text] isEqualToString: self.myView.passwordTextField.text]) {
NSLog(@"登陆成功");
}
NSLog(@"%@", self.myModel.Dictionary);
NSLog(@"12");
}
-(void)press {
RegisetController* regVc = [[RegisetController alloc] init];
regVc.delegate = self;
[self presentViewController:regVc animated:YES completion:nil];
regVc.myModel.Dictionary = self.myModel.Dictionary;
NSLog(@"12");
}
-(void)comfirm:(NSString *)account andPassord:(NSString *)passord {
[self.myModel.Dictionary setValue:passord forKey:account];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
这部分内容就是对于我们的登陆注册系统的一个MVC的架构,其实实现的效果和之前的登陆注册系统区别不大,但主要的在于我们优化了我们的代码,减少了有关Controller层的代码量。让我们的代码有更好的扩展性以及更加易于维护。
实现的效果:
从上面这个demo我们就可以看出他的优点就是将应用程序分离出不同的部分,降低代码的耦合度
优点:
但是这个架构也存在缺点,MVC 架构的缺点主要是由视图层和控制器层高度耦合造成的,负面影响主要为:
笔者简单学习了一下MVC模式的相关内容,MVC架构可以让我们可以更加方便的让我们理解一个项目的工作原理,同时也更方便我们针对性的修改相关代码的内容,笔者对于这部分的内容还是比较浅显,之后有了更深的理解会补充相关内容。