MVC简介
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写。
MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
MVC编程模式
MVC模式虽然是iOS编程中使用最广泛的模式,但论起复杂程度,MVC模式可以算是众多设计模式之首。通常情况下,MVC模式需要综合使用target-action模式、delegate模式、Notification或KVO模式等。
- Model(模型)表示应用程序核心(比如数据库记录列表),通常模型对象负责在数据库中存取数据。
- View(视图)显示数据(数据库记录),通常视图是依据模型数据创建的。
- Controller(控制器)处理输入(写入数据库记录),通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC原理可简化为下图:
- Controller和View之间可以通信,Controllor通过outlet(输出口)控制View,View可以通过target-action、delegate或者data source(想想UITableVeiwDatasource)来和Controller通信;
- Controller在接收到View传过来的交互事件(View就是完成让人和程序的交互的呀,比如按B1按钮)之后,经过一些判断和处理,把需要Model处理的事件递交给Model处理(比如刚才的例子中的保存到数据库),Controller对Model使用的是API;
- Model在处理完数据之后,如果有需要,会通过Notification或者KVO的方式告知Controller,事件已经处理完,Controller再经过判断和处理之后,考虑下一步要怎么办(是默默无闻的在后台操作,还是需要更新View,这得看Controller的“脸色”行事)。这里的无线天线很有意思,Model只负责发送通知,具体谁接收这个通知并处理它,Model并不关心,这一点非常重要,是理解Notification模式的关键。
- Model和View之间不直接通信!
以上摘自这篇博客
注册登陆实例
- 新建M V C三个文件夹(需要几个View建几套文件夹)
- 新建一个名为VView的类,继承自UIView(以登陆界面为例)
- 新建一个名为MModel的类,继承自NSObject
- 拖到相应的文件夹下,注册界面同上
- 新建一个跳转的界面,用于登陆后跳转
完成以后应该是这样:
按照MVC的思想,VView中应该写两个textField和两个button(以登陆界面为例),写好后的代码如下:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface VView : UIView
@property (nonatomic, strong) UIButton *loadBtn;
@property (nonatomic, strong) UIButton *registerBtn;
@property (nonatomic, strong) UITextField *nameTextField;
@property (nonatomic, strong) UITextField *passTextField;
- (void)InitView; //view初始化
@end
#import "VView.h"
@implementation VView
- (void)InitView {
_loadBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_loadBtn setFrame:CGRectMake(80, 400, 100, 50)];
[_loadBtn setTitle:@"load" forState:UIControlStateNormal];
[_loadBtn setTitleColor:[UIColor blackColor] forState: UIControlStateNormal];
[self addSubview:_loadBtn];
_registerBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_registerBtn setFrame:CGRectMake(230, 400, 100, 50)];
[_registerBtn setTitle:@"register" forState:UIControlStateNormal];
[_registerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self addSubview:_registerBtn];
_nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 200, 300, 50)];
_nameTextField.layer.masksToBounds = YES;
_nameTextField.layer.cornerRadius = 5;
_nameTextField.layer.borderWidth = 2;
_nameTextField.layer.borderColor = [UIColor blackColor].CGColor;
_nameTextField.placeholder = @"nameWord";
[self addSubview:_nameTextField];
_passTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 280, 300, 50)];
_passTextField.layer.masksToBounds = YES;
_passTextField.layer.cornerRadius = 5;
_passTextField.layer.borderWidth = 2;
_passTextField.layer.borderColor = [UIColor blackColor].CGColor;
_passTextField.secureTextEntry = YES;
_passTextField.placeholder = @"passWord";
[self addSubview:_passTextField];
}
会发现button里没有添加target-action方法,这是因为target-action方法需要设置一个target对象,在这个对象里调用action方法。按照MVC的思想,V里面不进行数据处理,而是要在C里面统一调控由C还是M来处理数据。本例中,我们是在C里面处理,所以我把targe-action方法写到C里面。
按照MVC的思想,M主要用于数据的处理,所以在这个案例中我将存放账号和密码的数组放入M中。
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MModel : NSObject
@property (nonatomic, strong) NSMutableArray *nameArr;
@property (nonatomic, strong) NSMutableArray *passArr;
- (void)modelInit;
//- (void)addName:(NSString *)name Pass:(NSString *)pass;
@end
#import "MModel.h"
@implementation MModel
- (void)modelInit {
_nameArr = [[NSMutableArray alloc] init];
_passArr = [[NSMutableArray alloc] init];
[_nameArr addObject:@"123"];
[_passArr addObject:@"456"];
}
接下来就是C了,登陆注册需要使用协议来传值,传值的操作我在这里就不解释了,不懂的朋友可以看看这篇博客,由于我在VView和MModel中定义的方法为实例方法,所以我需要实例化VView和MModel来调用这些方法:
#import <UIKit/UIKit.h>
#import "RViewController.h"
#import "VView.h"
#import "MModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface ViewController : UIViewController
<RegisterDelegate>
@property (nonatomic, strong) VView *myView;
@property (nonatomic, strong) MModel *myModel;
@end
#import "ViewController.h"
#import "newViewController.h"
#import "RViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_myView = [[VView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[_myView InitView];
[_myView.loadBtn addTarget:self action:@selector(pressLoad) forControlEvents:UIControlEventTouchUpInside];
[_myView.registerBtn addTarget:self action:@selector(pressRegister) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_myView];
_myModel = [[MModel alloc] init];
[_myModel modelInit];
}
- (void)pressLoad {
for (int i = 0; i < _myModel.nameArr.count; i++) {
if ([_myView.nameTextField.text isEqualToString: _myModel.nameArr[i]] && [_myView.passTextField.text isEqualToString:_myModel.passArr[i]]) {
newViewController *new = [[newViewController alloc] init];
[self presentViewController:new animated:NO completion:nil];
}
}
}
- (void)pressRegister {
RViewController *RegistViewController = [[RViewController alloc] init];
RegistViewController.registerDelegate = self;
[self presentViewController:RegistViewController animated:NO completion:nil];
}
- (void)passName:(NSString *)name passPass:(NSString *)pass {
[_myModel.nameArr addObject:name];
[_myModel.passArr addObject:pass];
}
到这里登陆界面就写完了,注册界面原理和它一样,我就只放代码不进行过多的讲解了
因为没有数据的改变,所以RModel里没有任何东西
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RModel : NSObject
@end
NS_ASSUME_NONNULL_END
#import "RModel.h"
@implementation RModel
@end
RView:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface RView : UIView
@property (nonatomic, strong) UIButton *loadBtn;
@property (nonatomic, strong) UIButton *registerBtn;
@property (nonatomic, strong) UITextField *nameTextField;
@property (nonatomic, strong) UITextField *passTextField;
- (void)InitView; //view初始化
@end
#import "RView.h"
@implementation RView
- (void)InitView {
_loadBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_loadBtn setFrame:CGRectMake(80, 400, 100, 50)];
[_loadBtn setTitle:@"back" forState:UIControlStateNormal];
[_loadBtn setTitleColor:[UIColor blackColor] forState: UIControlStateNormal];
[self addSubview:_loadBtn];
_registerBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_registerBtn setFrame:CGRectMake(230, 400, 100, 50)];
[_registerBtn setTitle:@"Ok" forState:UIControlStateNormal];
[_registerBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self addSubview:_registerBtn];
_nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 200, 300, 50)];
_nameTextField.layer.masksToBounds = YES;
_nameTextField.layer.cornerRadius = 5;
_nameTextField.layer.borderWidth = 2;
_nameTextField.layer.borderColor = [UIColor blackColor].CGColor;
_nameTextField.placeholder = @"nameWord";
[self addSubview:_nameTextField];
_passTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 280, 300, 50)];
_passTextField.layer.masksToBounds = YES;
_passTextField.layer.cornerRadius = 5;
_passTextField.layer.borderWidth = 2;
_passTextField.layer.borderColor = [UIColor blackColor].CGColor;
_passTextField.secureTextEntry = YES;
_passTextField.placeholder = @"passWord";
[self addSubview:_passTextField];
}
RViewController:
#import <UIKit/UIKit.h>
#import "RView.h"
#import "RModel.h"
NS_ASSUME_NONNULL_BEGIN
@protocol RegisterDelegate <NSObject>
- (void)passName:(NSString *)name passPass:(NSString *)pass;
@end
@interface RViewController : UIViewController
@property (nonatomic, strong) RView *myView;
@property (nonatomic, strong) RModel *myModel;
@property id <RegisterDelegate> registerDelegate;
@end
#import "RViewController.h"
#import "ViewController.h"
@interface RViewController ()
@end
@implementation RViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_myView = [[RView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[_myView InitView];
[_myView.loadBtn addTarget:self action:@selector(pressLoad) forControlEvents:UIControlEventTouchUpInside];
[_myView.registerBtn addTarget:self action:@selector(pressRegister) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_myView];
_myModel = [[RModel alloc] init];
}
- (void)pressLoad {
[self dismissViewControllerAnimated:NO completion:nil];
}
- (void)pressRegister{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"你已成功注册!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *sure = [UIAlertAction actionWithTitle:@"sure" style:UIAlertActionStyleCancel handler:^(UIAlertAction *sure) {
if ([self->_registerDelegate respondsToSelector:@selector(passName:passPass:)]) {
[self->_registerDelegate passName:self->_myView.nameTextField.text passPass:self->_myView.passTextField.text];
}
[self dismissViewControllerAnimated:NO completion:nil];
}];
[alert addAction:sure];
[self presentViewController:alert animated:NO completion:nil];
}