一、MVC模式的概念
MVC(Model-View-Controller)是一种软件设计模式,用于组织和管理应用程序的代码和逻辑。它将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller),每个组件负责不同的责任。MVC是cocoa应用良好设计的核心。采用这种模式的好处很多。这些应用程序中的许多对象往往更易于重复使用,其接口往往定义得更好。具有MVC设计的应用程序也比其他应用程序更容易扩展。此外,许多Cocoa技术和架构都基于MVC,并要求您的自定义对象扮演MVC角色之一。
模型对象(Model)
模型对象封装特定于应用程序的数据,并定义操作和处理该数据的逻辑和计算。例如,模型对象可能表示游戏中的角色或地址簿中的联系人。模型对象可能与其他模型对象有一对多关系,因此有时应用程序的模型层实际上是一个或多个对象图。作为应用程序持久状态一部分的大部分数据(无论持久状态存储在文件或数据库中)应在数据加载到应用程序后驻留在模型对象中。因为模型对象表示与特定问题域相关的知识和专业知识,所以它们可以在类似的问题域中重用。理想情况下,模型对象应该与视图对象没有显式连接,视图对象呈现其数据并允许用户编辑该数据。模型对象不应该涉及用户界面和呈现问题。
通信:视图层中创建或修改数据的用户操作通过控制器对象进行通信,并导致创建或更新模型对象。当模型对象更改时(例如,通过网络连接接收到新数据),它会通知控制器对象,控制器对象会更新相应的视图对象。
模型表示应用程序的数据和业务逻辑。 它通常包含数据结构、数据库操作、网络请求和应用程序的核心逻辑。
模型独立于用户界面,可以用于多个视图和控制器。
Model继承自NSObject
视图对象(View)
查看对象
视图对象是应用程序中用户可以看到的对象。视图对象知道如何绘制自身,并可以响应用户操作。视图对象的主要目的是显示来自应用程序模型对象的数据,并启用对该数据的编辑。尽管如此,视图对象通常与MVC应用程序中的模型对象分离。
因为您通常重用和重新配置它们,所以视图对象提供了应用程序之间的一致性。UIKit和AppKit框架都提供了视图类的集合,Interface Builder在其库中提供了数十个视图对象。
通信:查看对象通过应用程序的控制器对象了解模型数据的更改,并将用户发起的更改(例如,通过控制器对象在文本字段中输入的文本)传递给应用程序的模型对象。
视图负责展示模型的数据给用户,并处理用户界面的交互。 它通常由用户界面元素(如按钮、标签、图像等)组成。
视图应该尽量保持简单,只负责显示数据,而不包含业务逻辑。
View继承自UIView
控制器对象(Controller)
控制器对象
控制器对象充当一个或多个应用程序视图对象与其一个或更多模型对象之间的中介。因此,控制器对象是视图对象了解模型对象变化的管道,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。
通信:控制器对象解释视图对象中的用户操作,并将新的或更改的数据传输到模型层。当模型对象更改时,控制器对象将新的模型数据传递给视图对象,以便它们可以显示。
控制器作为模型和视图之间的中介,负责协调和管理它们之间的交互。
它接收用户的输入(例如点击按钮、滑动屏幕),更新模型的状态,并将更新的数据反映到视图上。
控制器还处理用户事件(如点击、手势),并触发相应的操作和逻辑。
Controller继承自UIViewController
MVC 的核心思想是将应用程序的逻辑(模型)与用户界面(视图和控制器)进行分离,以实现代码的可维护性和可扩展性。它使开发者可以更好地组织代码,降低不同组件之间的耦合度,并提供了更好的代码复用性和可测试性。
二、实现方法
以登录注册的demo为例,原来是将项目划分为注册和登录两个文件,使用MVC模式需要将文件划分成注册和登录两个文件,再将两个文件分别划分为Model、View、Controller三个文件
下面以登录界面为例,在model中,对于应用程序的数据和业务逻辑则是进行数据的存储,这里我使用数组存储数据。
#import "ModelLand.h"
@implementation ModelLand
- (void)initModel {
self.accountArray = [[NSMutableArray alloc] init];
self.passArray = [[NSMutableArray alloc] init];
}
@end
在View中,面向用户显示的UI元素:用户名、密码输入框和登录、注册按钮只需要通过实例方法初始化显示即可不需要写事件函数
#import <Foundation/Foundation.h>
@interface ViewLand : UIView
@property (nonatomic, strong)UITextField* accountTextField;
@property (nonatomic, strong)UITextField* passTextField;
@property (nonatomic, strong)UIButton* landBtn;
@property (nonatomic, strong)UIButton* registerBtn;
- (void)initLandView;
@end
#import "ViewLand.h"
@implementation ViewLand
- (void)initLandView {
self.accountTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 200, 300, 60)];
self.accountTextField.placeholder = @"请输入用户名";
self.accountTextField.secureTextEntry = NO;
self.accountTextField.keyboardType = UIKeyboardTypeDefault;
[self addSubview:self.accountTextField];
self.passTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 300, 300, 60)];
self.passTextField.placeholder = @"请输入密码";
self.passTextField.secureTextEntry = YES;
self.passTextField.keyboardType = UIKeyboardTypeDefault;
[self addSubview: self.passTextField];
self.landBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.landBtn.frame = CGRectMake(50, 400, 70, 40);
self.landBtn.backgroundColor = [UIColor grayColor];
self.landBtn.tintColor = [UIColor blackColor];
[self.landBtn setTitle:@"登录" forState:UIControlStateNormal];
[self addSubview:self.landBtn];
self.registerBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.registerBtn.frame = CGRectMake(200, 400, 70, 40);
self.registerBtn.backgroundColor = [UIColor grayColor];
self.registerBtn.tintColor = [UIColor blackColor];
[self.registerBtn setTitle:@"注册" forState:UIControlStateNormal];
[self addSubview: self.registerBtn];
}
@end
NS_ASSUME_NONNULL_END
在Controller中,需要将View和Model实现交互,因此在这里定义view的类和Model的类并进行实例化,并且在这里添加view的UI元素的事件函数。要实现两个MVC模式下文件的交互也只能通过Controller进行,因此也需要在当前Controller中定义另一个MVC模式下的Controller并实例化。
#import "ViewControllerLand.h"
#import "ModelLand.h"
#import "ViewLand.h"
#import "NextViewController.h"
#import "RegisterViewController.h"
@interface ViewControllerLand ()
@end
@implementation ViewControllerLand
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.viewLand = [[ViewLand alloc] init];
[self.viewLand initLandView];
self.viewLand.backgroundColor = [UIColor whiteColor];
self.viewLand.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
[self.viewLand.landBtn addTarget:self action:@selector(pressLand) forControlEvents:UIControlEventTouchUpInside];
[self.viewLand.registerBtn addTarget:self action:@selector(pressRegister) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.viewLand];
self.modelLand = [[ModelLand alloc] init];
[self.modelLand initModel];
}
- (void)pressLand {
NSLog(@"self.modelLand.accountArray:%@", self.modelLand.accountArray);
NSString* accountStr = self.viewLand.accountTextField.text;
NSString* passStr = self.viewLand.passTextField.text;
BOOL flag = NO;
for (int i = 0; i < self.modelLand.accountArray.count; i++) {
if ([accountStr isEqualToString:self.modelLand.accountArray[i]] && [passStr isEqualToString:self.modelLand.accountArray[i]]) {
flag = YES;
}
}
if (flag == YES) {
self.viewLand.accountTextField.text = @"";
self.viewLand.passTextField.text = @"";
NextViewController* nextViewController = [[NextViewController alloc] init];
nextViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nextViewController animated:YES completion:nil];
}
if (flag == NO) {
UIAlertController* alterController = [UIAlertController alertControllerWithTitle:@"提示" message:@"用户名或密码错误,请重新输入!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
self.viewLand.accountTextField.text = @"";
self.viewLand.passTextField.text = @"";
}];
[alterController addAction:action];
[self presentViewController:alterController animated:YES completion:nil];
}
}
- (void)pressRegister {
if (self.registerViewController == nil) {
self.registerViewController = [[RegisterViewController alloc] init];
}
self.registerViewController.modelRegister.accountArray = self.modelLand.accountArray;
self.registerViewController.modelRegister.passArray = self.modelLand.passArray;
self.registerViewController.delegate = self;
self.registerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
self.viewLand.accountTextField.text = @"";
self.viewLand.passTextField.text = @"";
[self presentViewController:self.registerViewController animated:YES completion:nil];
}
- (void)returnAccount:(NSMutableArray*)myAccountArr returnPass:(NSMutableArray*)myPassArr {
NSLog(@"myAccountArr:%@", myAccountArr);
self.modelLand.accountArray = myAccountArr;
self.modelLand.passArray = myPassArr;
}
运行结果如下: