MVC简介
MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
- Model(模型):表示应用程序核心(比如数据库记录列表),是应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据。
- View(视图):显示数据(数据库记录),通常视图是依据模型数据创建的。
- Controller(控制器):处理输入(写入数据库记录),是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC的优缺点
优点
- 耦合性低
视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码,因为模型与控制器和视图相分离,所以很容易改变应用程序的数据层。由于运用MVC的应用程序的三个部件是相互独立,改变其中一个不会影响其它两个,所以依据这种设计思想能构造良好的松耦合的构件。 - 重用性高
随着技术的不断进步,需要用越来越多的方式来访问应用程序。MVC模式允许使用各种不同样式的视图来访问同一个服务器端的代码,因为多个视图能共享一个模型。 - 可维护性高
缺点
- 没有明确的定义
完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。 - 不适合小型,中等规模的应用程序
- 增加系统结构和实现的复杂性
对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
MVC之间的通信
- 白色虚线:可直接引用到 Controller 中实例化;
- 白色实线:不可直接引用到 Controller 中实例化,需要用其他同步手段进行数据和状态的同步;
- 黄色实线:不可直接通信;
- Controller->Model/View
直接在Controller中引入并实例化Model和View
Model和View如何向Controller发送消息?
Model->Controller
-
KVO(监听)
Controller通过监听,监听Model的每个属性的变化来做出响应事件 -
Notification(通知)
Model中创建一个NSNotificationCenter,在Controller中,创建一个方法来接收通知。当Model发生变化时, 他会发送一个通知,而Controller会接收通知
View->Controller
-
target-Action
Controller给View添加一个target,当用户的触摸事件发生时,view产生action,Controller接收到之后做出相应的响应。 -
delegate 或 datasource
Controller可以作为view的代理,当View中检测到被触摸,他会通知Controller做出响应
实例代码(登陆注册demo)
- 创建三个文件夹,分别命名为M V C
- 新建LoginModel类,继承于NSObject
- 新建LoginView,继承于UIView
- 新建LoginViewController,继承于UIViewController
在LoginView中写出需要实现的两个button和两个textField
//LoginView.h中
@interface LoginView : UIView
@property (nonatomic, strong) UITextField *loginTextFiled;
@property (nonatomic, strong) UITextField *passTextFiled;
@property (nonatomic, strong) UIButton *loginButton;
@property (nonatomic, strong) UIButton *registerButton;
- (void) viewInit;//初始化View,在controller中调用
@end
//LoginView.m中
#import "LoginView.h"
@implementation LoginView
- (void) viewInit {
self.backgroundColor = [UIColor whiteColor];
_loginTextFiled = [[UITextField alloc] initWithFrame:CGRectMake(70, 260, 260, 50)];
[self addSubview:_loginTextFiled];
[_loginTextFiled setBorderStyle:UITextBorderStyleRoundedRect];
_loginTextFiled.layer.borderWidth = 3;
_loginTextFiled.layer.cornerRadius = 4;
_loginTextFiled.tintColor = [UIColor blackColor];
_loginTextFiled.placeholder = @"Name...";
_passTextFiled = [[UITextField alloc] initWithFrame:CGRectMake(70, 340, 260, 50)];
[self addSubview:_passTextFiled];
[_passTextFiled setBorderStyle:UITextBorderStyleRoundedRect];
_passTextFiled.layer.borderWidth = 3;
_passTextFiled.layer.cornerRadius = 4;
_passTextFiled.tintColor = [UIColor blackColor];
_passTextFiled.placeholder = @"Password...";
_passTextFiled.secureTextEntry = YES;
_loginButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self addSubview:_loginButton];
[_loginButton.layer setMasksToBounds:YES];
_loginButton.layer.borderWidth = 2;
_loginButton.layer.cornerRadius = 4;
_loginButton.frame = CGRectMake(60, 500, 120, 40);
[_loginButton setTitle:@"Login" forState:UIControlStateNormal];
[_loginButton setTintColor:[UIColor blackColor]];
_registerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self addSubview:_registerButton];
_registerButton.frame = CGRectMake(220, 500, 120, 40);
_registerButton.layer.borderWidth = 2;
_registerButton.layer.cornerRadius = 4;
[_registerButton setTitle:@"Regist" forState:UIControlStateNormal];
[_registerButton setTintColor:[UIColor blackColor]];
}
因为MVC方法中,View中不实现数据的处理,所以将target-action方法放在Controller中实现
在Model中放入数据(登陆时的账号和密码)
//LoginModel.h中
@interface LoginModel : NSObject
@property (nonatomic, strong) NSMutableArray *nameArr;
@property (nonatomic, strong) NSMutableArray *passArr;
- (void) modelInit;
@end
//LoginModel.m中
#import "LoginModel.h"
@implementation LoginModel
- (void) modelInit {
_nameArr = [[NSMutableArray alloc] init];
[_nameArr addObject:@"123"];
_passArr = [[NSMutableArray alloc] init];
[_passArr addObject:@"123"];
}
最后在Controller中实例化LoginModel和LoginView对其中的方法进行调用
//LoginViewController.h中
#import <UIKit/UIKit.h>
#import "LoginView.h"
#import "LoginModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface LoginViewController : UIViewController
@property (nonatomic, strong) LoginView *loginView;
@property (nonatomic, strong) LoginModel *loginModel;
@end
// LoginViewController.m中
#import "LoginViewController.h"
#import "RegisterViewController.h"
@interface LoginViewController () <RegisterDelegate>
@end
@implementation LoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
//self.view.backgroundColor
_loginView = [[LoginView alloc] initWithFrame:self.view.frame];
[self.view addSubview:_loginView];
[_loginView viewInit];
[_loginView.loginButton addTarget:self action:@selector(pressLogin) forControlEvents:UIControlEventTouchUpInside];
[_loginView.registerButton addTarget:self action:@selector(pressRegister) forControlEvents:UIControlEventTouchUpInside];
_loginModel = [[LoginModel alloc] init];
[_loginModel modelInit];
// Do any additional setup after loading the view.
}
- (void) pressLogin {
for (int i = 0; i < _loginModel.nameArr.count; i++) {
if ([_loginView.loginTextFiled.text isEqualToString:_loginModel.nameArr[i]] && [_loginView.passTextFiled.text isEqualToString:_loginModel.passArr[i]]) {
[self showError:@"您已成功登陆"];
}
else{
[self showError:@"用户名或密码错误!"];
}
}
}
- (void) pressRegister {
RegisterViewController *registerVC = [[RegisterViewController alloc] init];
registerVC.modalPresentationStyle = UIModalPresentationFullScreen;
registerVC.registerDelegate = self;
[self presentViewController:registerVC animated:YES completion:nil];
}
//协议传值
- (void) passData: (NSString *) name AndPassword: (NSString *) pass {
_loginView.loginTextFiled.text = name;
_loginView.passTextFiled.text = pass;
[_loginModel.nameArr addObject:name];
[_loginModel.passArr addObject:pass];
}
//弹出对话框
- (void) showError: (NSString *) message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"bling~" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"bingo" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
注册界面与登陆界面类似,多了协议传值
//RegisterViewController.m
#import "RegisterViewController.h"
@interface RegisterViewController ()
@end
@implementation RegisterViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_registerView = [[RegiserView alloc] initWithFrame:self.view.frame];
[self.view addSubview:_registerView];
[_registerView RviewInit];
[_registerView.cancelButton addTarget:self action:@selector(pressCancel) forControlEvents:UIControlEventTouchUpInside];
[_registerView.registerButton addTarget:self action:@selector(pressRegist) forControlEvents:UIControlEventTouchUpInside];
_registerModel = [[RegisterModel alloc] init];
}
- (void) pressRegist {
_registerModel.nameStr = _registerView.loginTextFiled.text;
_registerModel.passStr = _registerView.passTextFiled.text;
//传值
if ([_registerDelegate respondsToSelector:@selector(passData:AndPassword:)]) {
[_registerDelegate passData:_registerModel.nameStr AndPassword:_registerModel.passStr];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) pressCancel {
[self dismissViewControllerAnimated:YES completion:nil];
}