【iOS】MVC入门

news2024/12/25 8:53:12

【iOS】MVC模式的学习

文章目录

  • 【iOS】MVC模式的学习
    • 前言
    • MVC模式
      • 概念
      • MVC的交流模式
      • MVC的一个简单实践
        • Model层
        • View层
        • Controller层
      • MVC的优点与缺点
      • 总结

前言

笔者在暑假的学习中完成了一些小项目,这些小项目中间有时候出现了一个小bug都要寻找很久,而且会导致所有整个项目无法运行,这时候就更体现了我们一个优秀的项目需要满足的几个要求:高内聚,低耦合。 代码均摊,易于扩展,具有易用性。

我们创建一个控件,设置这个控件的样子,设置这个控件的交互方法,展示这个控件,都需要一定的代码量,控件少的时候还好,看得过去,但是控件一多,像下面这个App 的界面,各种控件就多起来了,这个时候如果还把他们都堆在一个ViewController 里面就不合适了,要改bug,要添加控件就会变得非常麻烦。

在这里插入图片描述

这时候我们就会发现我们的一个ViewController的代码会非常臃肿,修改代码也不方便。这时候我们就出现了一个MVC架构来解决这种代码臃肿的情况,尽可能的降低耦合度,实现一个代码均摊的效果。

MVC模式

概念

MVC是Model-VIew-Controller,就是模型-视图-控制器,MVC把软件系统分为三个部分:Model,View,Controller。其就是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

  • M:Model(模型)负责处理数据,以及处理部分的业务逻辑

通俗来说,就是你的程序是什么,就是你的程序将要实现的功能,或者是它所能干的事情。也就是微信消息列表里的人名字,信息内容,头像,是否屏蔽该人的消息等等数据,可以认为,Model 里面装满了这个程序的各种数据,它负责处理数据、以及处理部分的业务逻辑。

  • V:View(视图)负责数据的展示和事件捕捉

通俗来说,在屏幕上你所看到的,这里有一个UITableView,TableView 里面有UILabel,UIImageView,你在屏幕上看到的组件,都可以归类为View。

  • C:Controller / ViewController / VC(控制器)负责协调Model 和 View,处理大部分逻辑

它将数据从Model 层传送到View 层并展示出来,同时将View 层的交互传到Model 层以改变数据。大部分的逻辑操作(点击Button就是一种逻辑)都应该交由VC完成。

MVC的交流模式

苹果官方的图片

在这里插入图片描述

斯坦福大学公开课的图片

在这里插入图片描述

这张图展示了MVC架构中各个部分的关系,下面来介绍一下各个部分之间的联系:

  1. Controller与View之间可以进行交流,Controller可以通过outlet去控制View(输出口:控制器类可以通过一种特殊的属性来引用nib文件中的对象,可以把输出口看成是指向需要的对象的指针),而View通过,delegate,data source,target-action 来和Controller进行通信。
  2. Controller在接收到View传过来的Button的点击事件 经过判断处理后,可以选择下一步的具体操作过程,比如弹窗或者新界面的弹出。也可以交给Model处理,方法就是设置一个代理,从C将V传递的值再传递给M(比如在Model中通过判断后发布通知是否需要,Model在处理完数据之后,有时候可能会通过通知或者KVO的方式告知Controller,Model只负责通知,之后的操作由Controller决定)
  3. 注意这里的Model层和View层是一定不可以出现交互的。

MVC的一个简单实践

根据学长学姐的博客,我发现大部分学长都还是写了一个登陆注册的小demo来练习这个模式。

首先我们先要对相关的文件进行一个分类,根据不同的界面,划分成为不同MVC的模块

在这里插入图片描述

这里我们把登陆界面和注册界面分成两个部分,然后就是对于每一个层该怎么编写代码的问题了,这里以登陆界面的MVC来作为了示例

Model层

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

这个数据层你可以发现他仅仅包含了我们这里的一个账号密码的内容,然后重写一下初始化的函数。这里就完成了有关数据层的内容。

View层
#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子类进行初始化操作。**然后我们在这个子类中重新完成相关内容。

Controller层

这个层用来处理有关交互的逻辑部分

#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层的代码量。让我们的代码有更好的扩展性以及更加易于维护。

实现的效果:

在这里插入图片描述

MVC的优点与缺点

从上面这个demo我们就可以看出他的优点就是将应用程序分离出不同的部分,降低代码的耦合度

优点:

  • 通过将应用程序分离为这三个不同的组件,MVC 促进了模块化,从而可以更轻松地测试维护应用程序。
  • 职责分离还允许开发人员在应用程序的特定部分工作,而不会影响其他部分。这使得添加新功能或修改现有功能变得更加容易,而不会破坏应用程序的其他部分。
  • MVC 还促进了可重用性。由于这些组件是分开的并且具有特定的职责,因此它们可以在应用程序的其他部分或完全其他应用程序中重用。这可以节省开发时间降低应用程序的复杂性

但是这个架构也存在缺点,MVC 架构的缺点主要是由视图层和控制器层高度耦合造成的,负面影响主要为:

  1. **代码过于集中。**ViewController 因为将两部分高度耦合,它将处理交互、视图更新 布局、Model 数据获取和修改、导航等几乎所有操作。
  2. **难以进行测试。**由于高度耦合,使得以检测功能为主的单元测试需要配合特定视图才能进行,让测试难度陡增。所以,在 MVC 中,开发者一般只对 Model 进行测试。
  3. **难以扩展。**在 ViewController 中添加新功能需要格外小心,高度耦合的逻辑结构增加了出错的风险,同时,由于 View 和 Controller 部分互相依赖,增加新功能不仅可能需要大量修改原有代码,也会使 ViewController 愈发笨重。

总结

笔者简单学习了一下MVC模式的相关内容,MVC架构可以让我们可以更加方便的让我们理解一个项目的工作原理,同时也更方便我们针对性的修改相关代码的内容,笔者对于这部分的内容还是比较浅显,之后有了更深的理解会补充相关内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2116639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端学习笔记-Web APls篇-05

Bom操作 1.Window对象 1.1BOM(浏览器对象模型&#xff09; BOM(Browser Object Model ) 是浏览器对象模型 window对象是一个全局对象&#xff0c;也可以说是JavaScript中的顶级对象像document、alert()、console.log()这些都是window的属性&#xff0c;基本BOM的属性和方法都…

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT&#xff0c;这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频&#xff0c;并利用 SAM 2 进行 3D 空间分割&#xff0c;无需进一步训练或 2D-3D 投影。 我们的框架…

ML19_GMM高斯混合模型详解

1. 中心极限定理 中心极限定理&#xff08;Central Limit Theorem, CLT&#xff09;是概率论中的一个重要定理&#xff0c;它描述了在一定条件下&#xff0c;独立同分布的随机变量序列的标准化和的分布趋向于正态分布的性质。这个定理在统计学中有着广泛的应用&#xff0c;尤其…

算法篇_C语言实现霍夫曼编码算法

一、前言 霍夫曼编码&#xff08;Huffman Coding&#xff09;是一种广泛使用的数据压缩算法&#xff0c;特别适用于无损数据压缩。它是由David A. Huffman在1952年提出的&#xff0c;并且通常用于文件压缩和传输中减少数据量。霍夫曼编码的核心思想是使用变长编码表对源数据进…

提升效率必备!学习awk命令,轻松搞定数据

在日常的工作中&#xff0c;无论是数据处理、日志分析&#xff0c;还是格式化输出&#xff0c;AWK命令都是不可或缺的利器。AWK是一种强大的文本处理工具&#xff0c;能让你轻松处理复杂的数据&#xff0c;提升工作效率。本文将为你介绍AWK的基本功能及一些实用场景&#xff0c…

树 --- 二叉树

树的物理结构和逻辑结构上都是树形结构。 树形结构&#xff1a;由一个根和若干个子节点组成的集合。 最外围的为叶子节点&#xff1a;只有前驱而没有后继。 &#xff08;一&#xff09;树的性质 • ⼦树是不相交的 • 除了根结点外&#xff0c;每个结点有且仅有⼀个⽗结点 •…

每天五分钟玩转深度学习框架PyTorch:将nn的神经网络层连接起来

本文重点 前面我们学习pytorch中已经封装好的神经网络层,有全连接层,激活层,卷积层等等,我们可以直接使用。 如代码所示我们直接使用了两个nn.Linear(),这两个linear之间并没有组合在一起,所以forward的之后,分别调用了,在实际使用中我们常常将几个神经层组合在一起…

【EI会议征稿通知】第十一届机械工程、材料和自动化技术国际会议(MMEAT 2025)

第十一届机械工程、材料和自动化技术国际会议&#xff08;MMEAT 2025&#xff09; 2025 11th International Conference on Mechanical Engineering, Materials and Automation Technology 本次大会旨在汇聚全球机械工程、材料科学及自动化技术的创新学者和行业专家&#xff0…

使用 BentoML快速实现Llama-3推理服务

介绍 近年来&#xff0c;开源大模型如雨后春笋般涌现&#xff0c;为自然语言处理领域带来了革命性的变化。从文本生成到代码编写&#xff0c;从机器翻译到问答系统&#xff0c;开源大模型展现出惊人的能力&#xff0c;吸引了越来越多的开发者和企业投身其中。 然而&#xff0…

Subclass-balancing Contrastive Learning for Long-tailed Recognition

文章目录 SCL(supervised contrastive learning)1. 监督对比学习&#xff08;SCL&#xff09;的基本概念2. SCL的损失函数3. 长尾数据集的问题4. k-正样本对比学习&#xff08;KCL&#xff09;的引入5. 总结 SBCL举例说明&#xff1a;狗的分类 关键点&#xff1a;划分为多个子类…

4-1.Android Camera 之 CameraInfo 编码模板(前后置摄像头理解、摄像头图像的自然方向理解)

一、Camera.CameraInfo Camera.CameraInfo 是用于获取设备上摄像头信息的一个类&#xff0c;它提供摄像头的各种详细信息&#xff0c;例如&#xff0c;摄像头的方向、是否支持闪光灯等&#xff0c;以下是它的常用属性 static int CAMERA_FACING_BACK&#xff1a;表示设备的后置…

Protobuf库的使用

文章目录 Protobuf是什么Protobuf使⽤流程介绍ProtoBuf的使用创建.proto⽂件指定proto3语法package声明符定义消息&#xff08;message&#xff09;编译contacts.proto⽂件命令如下&#xff1a;序列化与反序列化的使⽤ Protobuf是什么 ProtoBuf&#xff08;全称ProtocolBuffer…

数字 FPV 革命 – DJI、Leadcore 和 Artosyn 的三角关系。

人们对 DJI、Caddx FPV 以及 HDZero 等公司最近推出的数字 FPV 系统的起源进行了大量的猜测和推测。随着 Avatar 系统的发布&#xff0c;也有许多人认为它要么使用与 DJI 相同的芯片组&#xff0c;要么是复制品或克隆品。在本文中&#xff0c;我将尝试揭开这一切的神秘面纱&…

python spider novel

python msedgedriver 获取小说 声明&#xff1a;只为学习/练习技术 from lxml import etree from selenium import webdriver from selenium.webdriver.edge.service import Service from selenium.webdriver.edge.options import Optionsimport time# 初始化EdgeOptions, 以…

【系统规划与管理师】【案例分析】【考点】【答案篇】第4章 IT服务规划设计

【问题篇】☞【系统规划与管理师】【案例分析】【考点】【问题篇】第4章 IT服务规划设计 【移动端浏览】☞【系统规划与管理师】【案例分析】【模拟考题】章节考题汇总&#xff08;第4章&#xff09;&#xff08;答案篇&#xff09;&#xff08;共38个知识点&#xff09; 第4章…

《数字信号处理》学习05-单位冲击响应与系统响应

目录 一&#xff0c;单位冲激响应 二&#xff0c;LTI系统对任意序列的系统响应 三&#xff0c;LTI系统的性质 通过上一篇文章《数字信号处理》学习04-离散时间系统中的线性时不变系统-CSDN博客的学习&#xff0c;我已经知道了离散时间线性时不变系统&#xff08;LTI&#x…

基于 jenkins 的持续测试方案

CI/CD Continuous Integration; Continuous Deployment; 持续集成&#xff0c;将新代码和旧代码一起打包、构建&#xff1b;持续部署&#xff0c;将新构建的包进行部署&#xff1b;持续测试&#xff0c;将新代码、新单元测试一起测试&#xff1b;方案&#xff1a; 公有云DevO…

Python 控制Chrome浏览器使用Selenium4操作点击百度搜索

前面我们讲到如何安装Selenium和ChromeDriver来驱动打开网页,现在我们有一个目的就是使用python来控制chrome浏览器打开百度并搜索 直接先上调试好的代码 from time import sleepfrom selenium import webdriver from selenium.webdriver.common.keys import Keys from selen…

2-88 基于matlab的四叉树加权聚焦多聚焦图像融合

基于matlab的四叉树加权聚焦多聚焦图像融合&#xff0c;的四叉树分解策略将源图像被分解成四叉树结构中具有最佳尺寸的块。在这个树形结构中&#xff0c;使用一种新的加权焦点测量方法&#xff08;名为加权修正拉普拉斯之和&#xff09;来检测焦点区域。可以很好地从源图像中提…

1934. 数字游戏(number)

代码 #include<bits/stdc.h> using namespace std; int main() {int ans0,i;string s;cin>>s;for(i0;i<7;i)if(s[i]1)ans;cout<<ans;return 0; } 记得点赞关注收藏&#xff01;&#xff01;&#xff01;谢谢&#xff01;&#xff01;&#xff01;