前言- cocoa pods还没配好,先学MVC
- 这是我暑假写demo的文件分类
- 暑期写demo的时候一旦出现bug就是毁灭性的打击,刚入手iOS,比如写一个登陆注册界面,有View(输入框和背景),点击Button时的触发事件,还有ViewController等等等等的转变都写在了一个文件里面,一旦报错就是几个小时没了,今天了解并尝试了iOS的一种设计模式- MVC设计模式
什么是MVC?
- MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式
官方解释(翻译)(图解)
Model Objects
-
- 模型对象封装特定于应用程序的数据,并定义操作和处理该数据的逻辑和计算。例如,模型对象可能表示游戏中的角色或地址簿中的联系人。模型对象可能与其他模型对象有一对多关系,因此有时应用程序的模型层实际上是一个或多个对象图。作为应用程序持久状态一部分的大部分数据(无论持久状态存储在文件或数据库中)应在数据加载到应用程序后驻留在模型对象中。因为模型对象表示与特定问题域相关的知识和专业知识,所以它们可以在类似的问题域中重用。理想情况下,模型对象应该与视图对象没有显式连接,视图对象呈现其数据并允许用户编辑该数据。模型对象不应该涉及用户界面和呈现问题。
-
- 通信:视图层中创建或修改数据的用户操作通过控制器对象进行通信,并导致创建或更新模型对象。当模型对象更改时(例如,通过网络连接接收到新数据),它会通知控制器对象,控制器对象会更新相应的视图对象。
View Objects
-
- 查看对象
视图对象是应用程序中用户可以看到的对象。视图对象知道如何绘制自身,并可以响应用户操作。视图对象的主要目的是显示来自应用程序模型对象的数据,并启用对该数据的编辑。尽管如此,视图对象通常与MVC应用程序中的模型对象分离。
因为您通常重用和重新配置它们,所以视图对象提供了应用程序之间的一致性。UIKit和AppKit框架都提供了视图类的集合,Interface Builder在其库中提供了数十个视图对象。
-
- 通信:查看对象通过应用程序的控制器对象了解模型数据的更改,并将用户发起的更改(例如,通过控制器对象在文本字段中输入的文本)传递给应用程序的模型对象。
Controller Objects
-
- 控制器对象
控制器对象充当一个或多个应用程序视图对象与其一个或更多模型对象之间的中介。因此,控制器对象是视图对象了解模型对象变化的管道,反之亦然。控制器对象还可以为应用程序执行设置和协调任务,并管理其他对象的生命周期。
-
- 通信:控制器对象解释视图对象中的用户操作,并将新的或更改的数据传输到模型层。当模型对象更改时,控制器对象将新的模型数据传递给视图对象,以便它们可以显示。
总结理解
- 参考博客 - MVC
- MVC模式能够完成各司其职的任务模式,由于降低了各个环节的耦合性,大大优化Controller的代码量,虽然M+V+C里面的代码总量比不使用MVC模式多了一些,但MVC模式写出来的代码层次分明,结构清楚,分工明确,为以后修改代码、调试程序都带来了极大的便利
-
- Model:负责业务逻辑、来自UI数据处理、本地数据、网络接收数据。
-
-
- Controller:负责View与Model间的消息的转发传递。
所以,Model继承自NSObject,View继承自UIView,Controller继承自UIViewController。
简单的看
- Model和View永远不能相互通信,只能通过Controller传递, Controller和View之间可以通信,Controllor通过outlet(输出口)控制View,View可以通过target-action、delegate或者data source(想想UITableVeiwDatasource)来和Controller通信;
Controller是View的代理(delegate),以同步View与Controller。
MVC小尝试-demo
- 看了我们组的博客,可能是传统吧,基本上都写的是登陆注册demo
预先理解
- 先看一下如何划分MVC
-
- 对于登陆注册,以前是写成2个文件,一个RegisterViewController,一个LoadViewConrtroller里面存放了需要多所有东西,对于MVC来说,需要划分2个文件,一个注册一个登陆,里面分别存放M,V,C三个小文件
思路分析的细节强调- Land界面为例
- 对于登陆界面,账号密码输入框是继承于UIView的,所以我们需要写一个实例方法初始化UIView
Viewland
(只需要显示出输入框和按钮即可,达到View的目的)
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ViewLand : UIView
@property (nonatomic ,strong)UITextField *nameTextField;
@property (nonatomic, strong)UITextField *passWordTextField;
@property (nonatomic, strong)UIButton* landButton;
@property (nonatomic, strong)UIButton* registerButton;
- (void)initView;
@end
NS_ASSUME_NONNULL_END
#import "ViewLand.h"
@implementation ViewLand
- (void) initView {
_landButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_landButton setFrame:CGRectMake(80, 400, 100, 50)];
[_landButton setTitle:@"load" forState:UIControlStateNormal];
[_landButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self addSubview:_landButton];
_registerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_registerButton setFrame:CGRectMake(230, 400, 100, 50)];
[_registerButton setTitle:@"register" forState:UIControlStateNormal];
[_registerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self addSubview:_registerButton];
_nameTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 200, 300, 50)];
_nameTextField.layer.masksToBounds = YES;
_nameTextField.layer.cornerRadius = 8.0;
_nameTextField.layer.borderWidth = 2;
_nameTextField.layer.borderColor = [UIColor blackColor].CGColor;
_nameTextField.placeholder = @"nameWord";
[self addSubview:_nameTextField];
_passWordTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 280, 300, 50)];
_passWordTextField.layer.masksToBounds = YES;
_passWordTextField.layer.cornerRadius = 8.0;
_passWordTextField.layer.borderWidth = 2;
_passWordTextField.layer.borderColor = [UIColor blackColor].CGColor;
_passWordTextField.secureTextEntry = YES;
_passWordTextField.placeholder = @"passWord";
[self addSubview: _passWordTextField];
}
@end
ViewControllerLand
作为控制器,我们需要定义两个成员变量一个是Viewland类,一个是ModelLand类,在这里实现交互功能(Button的点击事件,界面的跳转)
#import <UIKit/UIKit.h>
#import "ViewControllerLand.h"
#import "ModelLand.h"
#import "ViewLand.h"
#import "ViewControllerRegister.h"
NS_ASSUME_NONNULL_BEGIN
@interface ViewControllerLand : UIViewController<r1>
@property (nonatomic, strong)ViewLand *ViewLand;
@property (nonatomic, strong)ModelLand* ModelLand;
@end
#import "ViewControllerLand.h"
#import "viewController.h"
@interface ViewControllerLand ()
@end
@implementation ViewControllerLand
- (void)viewDidLoad {
[super viewDidLoad];
_ModelLand = [[ModelLand alloc] init];
[self.ModelLand init];
_ViewLand = [[ViewLand alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
[_ViewLand initView];
[self.view addSubview:_ViewLand];
[_ViewLand.landButton addTarget:self action:@selector(pressLand:) forControlEvents:UIControlEventTouchUpInside];
[_ViewLand.registerButton addTarget:self action:@selector(pressRegister:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)pressLand:(UIButton*)button {
int bool1 = 0;
for (int i = 0; i < _ModelLand.nameArray.count; i++) {
if ([_ViewLand.nameTextField.text isEqualToString:_ModelLand.nameArray[i]] && [_ViewLand.passWordTextField.text isEqualToString:_ModelLand.passWordArray[i]]) {
ViewController *new = [[ViewController alloc] init];
[self presentViewController:new animated:NO completion:nil];
bool1 = 1;
}
}
if (bool1 == 0) {
UIAlertController *_alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"验证失败,用户名或密码错误,请检查!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *sure = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
[_alert addAction:sure];
[self presentViewController:_alert animated:YES completion:nil];
}
}
- (void)pressRegister: (UIButton*)button {
ViewControllerRegister *RegistViewController = [[ViewControllerRegister alloc] init];
RegistViewController.registerDelegate = self;
[self presentViewController:RegistViewController animated:NO completion:nil];
}
- (void) passName:(NSString *) name passPass:(NSString *)pass {
[_ModelLand.nameArray addObject:name];
[_ModelLand.passWordArray addObject:pass];
}
@end
ModelLand
- 数据分析,对于登陆注册界面数据的分析和计算在这里就是账号密码的存储,所以这里存放2个数组
@interface ModelLand : NSObject
@property (nonatomic, strong)NSMutableArray* nameArray;
@property (nonatomic, strong)NSMutableArray* passWordArray;
- (void)landInit;
@end
@implementation ModelLand
- (void)landInit {
_nameArray = [[NSMutableArray alloc] init];
_passWordArray = [[NSMutableArray alloc] init];
}
@end
- Register也是同理在此不多叙述,需要注意的是我们需要把LandViewController作为根视图,在ViewController这样写(把版本调成iOS15以下,iOS15以上我还没有找到正确的获取winodw的方法)
- (void)viewDidLoad {
[super viewDidLoad];
ViewControllerLand* ViewLand1 = [[ViewControllerLand alloc] init];
ViewLand1.view.backgroundColor = [UIColor whiteColor];
UIWindow* window = [UIApplication sharedApplication].windows[0];
window.rootViewController = ViewLand1;
}
写完demo的认识
- 效果图如上,其实和写在一个文件里的区别不大,主要是MVC模式让我们更深刻清楚的理解了一个项目的工作原理和分工,界面是界面,控制器是控制器,要修改显示就修改View里的代码,修改交互过程即修改ViewController即可,后续多使用MVC,熟悉iOS最基础的设计模式