iOS中的MVVM设计模式
目录
前言
一、MVVM简介
二、MVVM的核心思想
三、MVVM的优势
四、MVVM在iOS中的实现
1. 创建Model
2. 创建ViewModel
3. 创建View
4. 主入口
总结
前言
随着iOS开发的发展,构建可维护和可扩展的代码架构变得至关重要。Model-View-ViewModel (MVVM) 是一种设计模式,通过分离UI和业务逻辑,使代码更具可读性和可测试性。本文将介绍MVVM模式在iOS中的使用,并通过一个简单的示例展示其实现方法。
一、MVVM简介
MVVM模式将应用程序分为三部分:
- Model:处理数据和业务逻辑。
- View:负责展示UI和处理用户交互。
- ViewModel:充当View与Model之间的桥梁,将数据和逻辑从Model传递给View,并将用户交互从View传递回Model。
这种分离有助于简化代码,使各部分职责更为明确,从而提高代码的可维护性和可测试性。
二、MVVM的核心思想
在MVVM模式中,ViewModel通过绑定的方式将数据传递给View。当Model中的数据发生变化时,ViewModel会通知View进行更新。反之,当用户在View中进行操作时,ViewModel会将这些操作传递给Model。
三、MVVM的优势
下面我们将通过一个示例展示如何在iOS中使用MVVM模式。
MVVM有三大优势:
1.分离关注点:通过将UI和业务逻辑分离,减少了代码耦合,提高了代码的可维护性。
2.可测试性:由于业务逻辑集中在ViewModel中,可以方便地对其进行单元测试,而无需依赖UI。
3.代码复用:ViewModel中封装的逻辑可以在多个View中复用,提高了代码的复用性。
四、MVVM在iOS中的实现
1. 创建Model
Model负责处理数据。在这个示例中,我们将创建一个简单的User模型和UserService来模拟数据获取。
// User.h
#import <Foundation/Foundation.h>@interface User : NSObject@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;@end// User.m
#import "User.h"@implementation User- (instancetype)initWithName:(NSString *)name age:(NSInteger)age {self = [super init];if (self) {_name = name;_age = age;}return self;
}@end// UserService.h
#import <Foundation/Foundation.h>
#import "User.h"@interface UserService : NSObject- (void)fetchUserWithCompletion:(void (^)(User *user))completion;@end// UserService.m
#import "UserService.h"@implementation UserService- (void)fetchUserWithCompletion:(void (^)(User *))completion {// 模拟网络请求User *user = [[User alloc] initWithName:@"John Doe" age:30];completion(user);
}@end
2. 创建ViewModel
ViewModel负责处理业务逻辑和数据转换。
// UserViewModel.h
#import <Foundation/Foundation.h>
#import "User.h"
#import "UserService.h"@interface UserViewModel : NSObject@property (nonatomic, strong) User *user;
@property (nonatomic, strong) UserService *userService;- (void)fetchUser;@end// UserViewModel.m
#import "UserViewModel.h"@implementation UserViewModel- (instancetype)init {self = [super init];if (self) {_userService = [[UserService alloc] init];}return self;
}- (void)fetchUser {__weak typeof(self) weakSelf = self;[self.userService fetchUserWithCompletion:^(User *user) {weakSelf.user = user;}];
}@end
3. 创建View
View负责展示数据和处理用户交互。
// UserViewController.h
#import <UIKit/UIKit.h>
#import "UserViewModel.h"@interface UserViewController : UIViewController@end// UserViewController.m
#import "UserViewController.h"@interface UserViewController ()@property (nonatomic, strong) UserViewModel *viewModel;
@property (nonatomic, strong) UILabel *nameLabel;@end@implementation UserViewController- (void)viewDidLoad {[super viewDidLoad];self.viewModel = [[UserViewModel alloc] init];self.nameLabel = [[UILabel alloc] initWithFrame:CGRectZero];self.nameLabel.translatesAutoresizingMaskIntoConstraints = NO;[self.view addSubview:self.nameLabel];[NSLayoutConstraint activateConstraints:@[[self.nameLabel.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],[self.nameLabel.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]]];[self bindViewModel];[self.viewModel fetchUser];
}- (void)bindViewModel {[self.viewModel addObserver:self forKeyPath:@"user" options:NSKeyValueObservingOptionNew context:nil];
}- (void)dealloc {[self.viewModel removeObserver:self forKeyPath:@"user"];
}- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {if ([keyPath isEqualToString:@"user"]) {self.nameLabel.text = self.viewModel.user.name;}
}@end
4. 主入口
// AppDelegate.h
#import <UIKit/UIKit.h>@interface AppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@end// AppDelegate.m
#import "AppDelegate.h"
#import "UserViewController.h"@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];UserViewController *viewController = [[UserViewController alloc] init];self.window.rootViewController = viewController;[self.window makeKeyAndVisible];return YES;
}@end
总结
通过上述示例,我们展示了如何在iOS中使用MVVM模式来构建一个简单的应用程序。MVVM模式通过分离UI和业务逻辑,提高了代码的可维护性和可测试性。虽然这个示例比较简单,但在实际项目中,MVVM模式可以帮助我们更好地管理复杂的UI和业务逻辑,从而构建高质量的iOS应用程序。希望这篇文章能帮助你理解和应用MVVM模式到你的iOS项目中。
相关文章:
iOS中的MVVM设计模式
目录 前言 一、MVVM简介 二、MVVM的核心思想 三、MVVM的优势 四、MVVM在iOS中的实现 1. 创建Model 2. 创建ViewModel 3. 创建View 4. 主入口 总结 前言 随着iOS开发的发展,构建可维护和可扩展的代码架构变得至关重要。Model-View-ViewModel (MVVM) 是一种…...

ES中的数据类型学习之ARRAY
Arrays | Elasticsearch Guide [7.17] | Elastic 中文翻译 :Array Elasticsearch 5.4 中文文档 看云 Arrays In Elasticsearch, there is no dedicated array data type. Any field can contain zero or more values by default, however, all values in the a…...
vue网络请求
post网络请求 import axios from axios import {ElMessage, ElLoading} from "element-plus" import { nextTick } from "vue" import JSONbig from json-bigint import { userToken } from "/constants/Constant.js";const defaultConfig {bas…...

几何光学基本原理——费马原理和射线方程
在几何光学中,射线方程用于描述光在折射率不均匀的介质中传播的路径。折射率的变化会导致射线发生弯曲,射线方程正是用于计算这种弯曲路径的。 几何光学的基本原理 几何光学假设光在介质中沿直线传播,但在折射率变化的介质中,光的…...
OpenCV车牌识别技术详解
第一部分:图像预处理 车牌识别(License Plate Recognition,LPR)是计算机视觉领域的一个重要应用,它涉及到图像处理、模式识别等多个方面。OpenCV作为一个强大的计算机视觉库,提供了丰富的车牌识别相关功能…...
解决llama_index中使用Ollama出现timed out 问题
现象: File "~/anaconda3/envs/leo_py38/lib/python3.8/site-packages/httpx/_transports/default.py", line 86, in map_httpcore_exceptionsraise mapped_exc(message) from exc httpx.ReadTimeout: timed out代码: from llama_index.core …...

Python爬虫技术 第14节 HTML结构解析
HTML 结构解析是 Web 爬虫中的核心技能之一,它允许你从网页中提取所需的信息。Python 提供了几种流行的库来帮助进行 HTML 解析,其中最常用的是 BeautifulSoup 和 lxml。 1. 安装必要的库 首先,你需要安装 requests(用于发送 HTT…...

【vue3|第18期】Vue-Router路由的三种传参方式
日期:2024年7月17日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^ 1.01365 = 37.7834;0.99365 = 0.0255 1.02365 = 1377.408…...

ElasticSearch(六)— 全文检索
一、match系列查询 前面讲到的query中的查询,都是精准查询。可以理解成跟在关系型数据库中的查询类似。match系列的查询,是全文检索的查询。会通过分词进行评分,匹配,再返回搜索结果。 1.1 match 查询 "query": {&qu…...

Oracle核心进程详解并kill验证
Oracle核心进程详解并kill验证 文章目录 Oracle核心进程详解并kill验证一、说明二、核心进程详解2.1.PMON-进程监控进程2.2.SMON-系统监控进程2.3.DBWn-数据库块写入进程2.4. LGWR-日志写入器进程2.5. CKPT-检查点进程 三、Kill验证3.1.kill ckpt进程3.2.kill pmon进程3.3.kill…...

【BUG】已解决:SyntaxError:positional argument follows keyword argument
SyntaxError:positional argument follows keyword argument 目录 SyntaxError:positional argument follows keyword argument 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,…...

怎样在 Nginx 中配置基于请求客户端 Wi-Fi 连接状态的访问控制?
🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会! 文章目录 怎样在 Nginx 中配置基于请求客户端 Wi-Fi 连接状态的访问控制一、理解请求客户端 Wi-Fi 连接状态二、Nginx 中的访问控制基础知识三、获取客户端 Wi-Fi 连接状态…...

逆向案例二十九——某品威客登录,请求头参数加密,简单webpack
网址:登录- 一品威客网,创新型知识技能共享服务平台 抓到登陆包分析,发现请求头有参数加密,直接搜索 定位到加密位置,打上断点,很明显是对象f的a方法进行了加密。 往上找f,可以发现f被定义了,是…...

河道高效治理新策略:视频AI智能监控如何助力河污防治
一、背景与现状 随着城市化进程的加快,河道污染问题日益严重,对生态环境和居民生活造成了严重影响。为了有效治理河道污染,提高河道管理的智能化水平,TSINGSEE青犀提出了一套河污治理视频智能分析及管理方案。方案依托先进的视频…...
[React]如何提高大数据量场景下的Table性能?
[React]如何提高大数据量场景下的Table性能? 两个方向:虚拟列表,发布订阅 虚拟列表 虚拟列表实际上只对可视区域的数据项进行渲染 可视区域(visibleHeight): 根据屏幕可视区域动态计算或自定义固定高度数据渲染项&…...

基于Vision Transformer的mini_ImageNet图片分类实战
【图书推荐】《PyTorch深度学习与计算机视觉实践》-CSDN博客 PyTorch计算机视觉之Vision Transformer 整体结构-CSDN博客 mini_ImageNet数据集简介与下载 mini_ImageNet数据集节选自ImageNet数据集。ImageNet是一个非常有名的大型视觉数据集,它的建立旨在促进视觉…...
JS中map()使用记录
优点和缺点 总的来说,map() 方法是一个强大的工具,适合于需要将数组中的每个元素转换为新形式的情况。然而,对于性能敏感的应用或需要更复杂控制逻辑的场景,可能需要考虑其他方法。 优点: 函数式编程风格:…...

JavaWeb学习——请求响应、分层解耦
目录 一、请求响应学习 1、请求 简单参数 实体参数 数组集合参数 日期参数 Json参数 路径参数 总结 2、响应 ResponseBody&统一响应结果 二、分层解耦 1、三层架构 三层架构含义 架构划分 2、分层解耦 引入概念 容器认识 3、IOC&DI入门 4、IOC详解 …...
Vue中!.和?.是什么意思
在Vue(或更广泛地说,在JavaScript和TypeScript中),!. 和 ?. 是两个与可选链(Optional Chaining)和断言非空(Non-null Assertion)相关的操作符,它们分别用于处理可能为nu…...

秋招突击——7/22——复习{堆——前K个高频元素}——新作{回溯——单次搜索、分割回文串。链表——环形链表II,合并两个有序链表}
文章目录 引言复习堆堆——前K个高频元素个人实现复习实现二参考实现 新作单词搜索个人实现参考实现 分割回文串个人实现参考实现 环形链表II个人实现参考实现 两个有序链表个人实现 总结 引言 又是充满挑战性的一天,继续完成我们的任务吧!继续往下刷&a…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...