iOS中的MVVM设计模式

目录

前言

一、MVVM简介

二、MVVM的核心思想

三、MVVM的优势

四、MVVM在iOS中的实现

1. 创建Model

2. 创建ViewModel

3. 创建View

4. 主入口

总结


前言

        随着iOS开发的发展,构建可维护和可扩展的代码架构变得至关重要。Model-View-ViewModel (MVVM) 是一种设计模式,通过分离UI和业务逻辑,使代码更具可读性和可测试性。本文将介绍MVVM模式在iOS中的使用,并通过一个简单的示例展示其实现方法。

一、MVVM简介

        MVVM模式将应用程序分为三部分:

  1. Model:处理数据和业务逻辑。
  2. View:负责展示UI和处理用户交互。
  3. 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项目中。

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

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

相关文章

【STM32】超声波一般常用哪两个引脚?

在STM32单片机中&#xff0c;超声波模块HC-SR04通常使用PA6和PA7引脚进行驱动。 在STM32单片机上使用HC-SR04超声波模块时&#xff0c;常用的引脚是PA6和PA7。其中&#xff0c;PA6用于发送触发信号到Trig引脚&#xff0c;而PA7用于接收Echo引脚的回响信号。这两个引脚通过适当的…

pdf2image:将PDF文档转化为图像的Python魔法

标题&#xff1a;探索pdf2image&#xff1a;将PDF文档转化为图 像的Python魔法 背景 在数字时代&#xff0c;我们经常需要处理各种格式的文档&#xff0c;尤其是PDF文件。PDF以其跨平台的可读性和稳定性而广受欢迎。然而&#xff0c;有时我们需要将PDF文件转换成图像格式&am…

springboot3-web-questions-分析

系列文章目录 文章目录 目录 系列文章目录 文章目录 前言 一、问题案例 1、maven项目compile时候出现告警warn 2、java文件打包然后在命令行中运行java会找不到主类 3、程序找不到数据库驱动和配置实例 4、springboot和mybatis-plus版本不兼容导致 5、springboot项目启动的解释…

sklearn中的增量学习:特征提取的艺术

sklearn中的增量学习&#xff1a;特征提取的艺术 在机器学习领域&#xff0c;特征提取是构建有效模型的关键步骤。然而&#xff0c;并非所有数据集都适合一次性加载到内存中进行处理&#xff0c;尤其是在处理大规模数据集时。Scikit-learn&#xff08;sklearn&#xff09;提供…

21、Python之面向对象:一切皆对象,可你真的需要面向对象吗

引言 面向对象&#xff08;Object-Oriented Programming, OOP&#xff09;和面向过程&#xff08;Procedural Programming&#xff09;是两种不同的编程范式。不能因为我们接下来要进入“面向对象”的模块的学习&#xff0c;就武断地说&#xff0c;面向对象一定比面向过程好。…

若依 ruoyi poi Excel合并行的导入

本文仅针对文字相关的合并做了处理 &#xff0c;图片合并及保存需要另做处理&#xff01;&#xff01; 目标&#xff1a;Excel合并行内容的导入 结果&#xff1a; 1. ExcelUtil.java 类&#xff0c;新增方法&#xff1a;判断是否是合并行 /*** 新增 合并行相关代码&#xff1a;…

【MySQL篇】Percona XtraBackup标准化全库完整备份策略(第三篇,总共五篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

计网_数据通信基础知识

2024.07.05&#xff1a;计算机网络数据通信基础知识学习笔记 第2节 数据通信基础知识 2.1 物理层特性&#xff08;学会区分&#xff09;2.2 信道相关的基本概念2.2.1 数字信号的&#xff08;基带调制&#xff09;&#xff08;1&#xff09;不归零NRZ编码&#xff08;2&#xff…

大模型日报 2024-07-25

大模型日报 2024-07-25 大模型资讯 Meta发布开源AI模型Llama 3.1 405B 摘要: Meta于周二宣布推出Llama 3.1 405B&#xff0c;这是一款大型语言模型&#xff0c;旨在与Anthropic、谷歌和OpenAI的顶级模型竞争。 Meta发布全球最大AI模型Llama 3.1 405B 摘要: Meta今日发布了其迄今…

在Typescript + Pinia 中使用 Actions

文件准备 type.ts import type { PiniaCustomProperties, StateTree, StoreDefinition, _GettersTree, _StoreWithGetters, _StoreWithState } from pinia; import type { UnwrapRef } from vue;/**构建 Actions */ type CreateActions<Id extends string, S extends StateT…

1207. 有趣的数字图形IV

问题描述 输入一个整数 &#x1d45b; &#xff08; &#x1d45b;≤12 &#xff09;&#xff0c;打印出如下要求的方阵&#xff1a; 除掉右上到左下对角线上的数外的右下半个区域中每个元素等于左边的和上面的元素之和。每个元素场宽为 5 。左上半个区域为空。 输入 一个整…

C语言------指针讲解(3)

一、字符指针 在指针中&#xff0c;我们知道有一类指针类型为字符指针char*; int main() {char ch w;char* pc &ch;*pc w;return 0; } 还有一种使用方式如下&#xff1a; 上述代码中&#xff0c;本质是把hello的首字符的地址放到了pstr中。即把一个常量字符串的首字符…

C++图书管理系统

目录 实现功能 用户管理 图书管理 借阅与归还 未归还图书 部分效果图 结构体 Book 结构体 User 结构体 源代码 编译时在连接器命令行加入 完整代码 实现功能 用户管理 添加用户&#xff1a;输入用户ID、用户名和密码…

【LeetCode】71.简化路径

1. 题目 2. 分析 3. 代码 我写了一版很复杂的代码&#xff1a; class Solution:def simplifyPath(self, path: str) -> str:operator [] # 操作符的栈dir_name [] # 文件名的栈idx 0cur_dir_name ""while(idx < len(path)):if path[idx] /:operator.ap…

ffmpeg 怎样分析ts 流中的 sdt 表

--------------------------------------------------------- author:hjjdebug date: 2024年 07月 24日 星期三 10:34:08 CST descriptor: ffmpeg 怎样分析ts 流中的 sdt 表 --------------------------------------------------------- 1. sdt 的概念 sdt 就是服务描述表&a…

提高性能的常见技术

1.数据库层面&#xff1a; 读写分离&#xff0c;对于大部分业务来说&#xff0c;读取操作要大于写入&#xff0c;同一个库&#xff0c;既读又写的话&#xff0c;负载会比较重&#xff0c;拆分为读库和写入库&#xff0c;可以降低数据库的负载&#xff0c;分时或延迟将写入的数…

AI绘画入门实践|Midjourney:使用 --seed 制作情侣头像与漫画

在 Midjourney 中&#xff0c;seed 是指一个种子&#xff0c;用于生成图像时的起点或基础。 使用格式&#xff1a;--seed 获取的seed值 获取 seed 值 使用 seed 生成图像 a cute boys avatar, background with blue sky and white cloud, Ghibli Studio style, Hayao Miyazaki…

【电子数据取证】网络钓鱼邮件取证:从识别到追踪

文章关键词&#xff1a;电子数据取证、邮件取证、电脑取证 一、前言 在数字化时代&#xff0c;电子邮件已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;随着技术的不断发展&#xff0c;网络钓鱼邮件这一威胁也日益猖獗&#xff0c;对个人隐私、企业安全乃至国…

Linux的RPM包 -- 制作

1.简单实现rpm包的制作 1.首先我们需要编写源代码 2.把源代码打包成压缩包 3.在自定义的路径下创建一个rpmbuild文件目录,其中必须包括有{SPECS,SOURCES,RPMS,SRPMS,BUILD,BUILDROOT}这几个文件目录 4.将压缩包存储到SOURCE中 5.在SPECS文件目录中创建一个spec file文件,对其进…

铁塔二轮充电桩协议对接稳定运营大数据面板汽车充电桩系统

信号标准名 信号类型 单位 备注 信号量ID 枚举值 告警级别新设备标准 充电口状态 遥测 0&#xff1a;待连接 05102001 1&#xff1a;空闲 2&#xff1a;充电中 3&#xff1a;已充满 4&#xff1a;异常 5&#xff1a;掉线 电压 遥测 V100 总电压放大100倍 05104001 电流 …