[HMLY]11.MVVM架构
概要
MVC架构,Model-View-Controller,如图一所示为一个典型的MVC设置。

- Model呈现数据
- View呈现用户界面
- Controller调节两者之间的交互。从Model取数据,显示在View中。
典型的MVC应用里,许多逻辑被放在View Controller中,他们中一些确实属于View Controller,但更多的是表现逻辑,即将Model中数据转换为View可以呈现的内容的事情。例如将JSON包里的某个NSDate转换为特定格式的NSString。这也导致了MVC被人称作Massive-View-Controller(重量级视图控制器)。
通常Controller中应该只放如下代码:
- 初始化时构造相应的View和Model
- 监听Model层的事件,将Model层的数据传递到View层
- 监听View层的时间,将View层的事件传递到Model层
仅此而已,除此之外的任何逻辑都不应该放到Controller中。因此这也就有了MVVM
MVVM
图二所示为MVVM设置:MVVM其实就是MVC的增强版。我们正式连接了View 和View Controller,并将表示逻辑从Controller中移出,放到了一个新的对象里,即View Model中。

这样做可带来如下的益处:
- 减少View Controller的复杂性,使得表示逻辑易于测试。
- 兼容MVC模式
- MVVM 配合一个绑定机制效果最好
举例
下面是一个看一个简单的 Person Model 以及相应的 View Controller。
@interface Person : NSObject
- (instancetype)initwithSalutation:(NSString *)salutation firstName:(NSString *)firstName lastName:(NSString *)lastName birthdate:(NSDate *)birthdate;
@property (nonatomic, readonly) NSString *salutation;
@property (nonatomic, readonly) NSString *firstName;
@property (nonatomic, readonly) NSString *lastName;
@property (nonatomic, readonly) NSDate *birthdate;
@end
- 现在假设有一个 PersonViewController,在
viewDidLoad
里,只需要基于它的 model属性设置一些Label即可。
- (void)viewDidLoad {
[super viewDidLoad];
if (self.model.salutation.length > 0) {
self.nameLabel.text = [NSString stringWithFormat:@"%@ %@ %@",self.model.salutation,self.model.firstName, self.model.lastName];
} else {
self.nameLabel.text = [NSString stringWithFormat:@"%@ %@", self.model.firstName,self.model.lastName];
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"EEEE MMMM d, yyyy"];
self.birthdateLabel.text = [dateFormatter stringFromDate:model.birthdate];
}
- 现在来看怎样通过一个ViewModel来增强它。
//ViewModel.h
@interface PersonViewModel : NSObject
- (instancetype)initWithPerson:(Person *)person;
@property (nonatomic, readonly) Person *person;
@property (nonatomic, readonly) NSString *nameText;
@property (nonatomic, readonly) NSString *birthdateText;
@end
ViewModel实现如下
//ViewModel.m
@implementation PersonViewModel
- (instancetype)initWithPerson:(Person *)person {
self = [super init];
if (!self) return nil;
_person = person;
if (person.salutation.length > 0) {
_nameText = [NSString stringWithFormat:@"%@ %@ %@", self.person.salutation, self.person.firstName, self.person.lastName];
} else {
_nameText = [NSString stringWithFormat:@"%@ %@", self.person.firstName, self.person.lastName];
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"EEEE MMMM d, yyyy"];
_birthdateText = [dateFormatter stringFromDate:person.birthdate];
return self;
}
@end
现在我们已将viewDidLoad
中的表示逻辑放入我们的 View Model 里了。此时,我们新的 viewDidLoad
就会非常轻量:
- (void)viewDidLoad { [super viewDidLoad];
self.nameLabel.text = self.viewModel.nameText;
self.birthdateLabel.text = self.viewModel.birthdateText;
}
MVVM作用与问题
MVVM在实际使用时也有一定的问题,主要体现在两点:
- 数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。
- 对于过大的项目,数据绑定需要花费更多的内存。
ReactiveCocoa
MVVM引出了一个ReactiveCocoa,ReactiveCocoa作用如图三所示:

如果想要深入了解ReactiveCocoa,可以看下ReactiveCocoa这篇文章。
[HMLY]11.MVVM架构的更多相关文章
- ReactiveCocoa常见操作方法介绍/MVVM架构思想
1.ReactiveCocoa常见操作方法介绍. 1.1 ReactiveCocoa操作须知 所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中, ...
- MVVM架构~目录
回到占占推荐博客索引 MVVM在概念上是真正将页面与数据逻辑分离的模式,在开发方式上,它是真正将前台代码开发者(JS+HTML)与后台代码开发者分离的模式(asp,asp.net,php,jsp).在 ...
- MVVM架构~Knockoutjs系列之验证机制的引入
返回目录 对于Knockoutjs本身来说,没有提供验证模块,不过,有第三方的扩展,就像你为jquery库作extensions一样,这讲中我将介绍一个Knockout插件扩展,knockout.va ...
- MVVM架构~使用boxy和knockoutjs实现编辑功能
返回目录 这个功能我认为非常有用,尤其在后台管理系统中,它对用户来说,使用体验这块非常不错,下面是它的截图
- MVVM架构的一次实践,重写iOS头条客户端
前言: 一个iOS头条APP,使用MVVM架构实现,代码中有注释,封装了AFN网络请求,解媾代码,使用起来非常方便.用最经典的TableView展示,后续不断更新,喜欢就star或fork一下,有问题 ...
- MVVM架构~knockoutjs系列之表单添加(验证)与列表操作源码开放
返回目录 本文章应该是knockoutjs系列的最后一篇了,前几篇中主要讲一些基础知识,这一讲主要是一个实际的例子,对于一个对象的添加与编辑功能的实现,并将项目源代码公开了,共大家一起学习! knoc ...
- WPF MVVM 架构 Step By Step(6)(把actions从view model解耦)
到现在为止,我们创建了一个简单的MVVM的例子,包含了实现了的属性和命令.我们现在有这样一个包含了例如textbox类似的输入元素的视图,textbox用绑定来和view model联系,像点击but ...
- iOS MVVM架构总结
为什么使用MVVM iOS中,我们使用的大部分都是MVC架构.虽然MVC的层次明确,但是由于功能日益的增加.代码的维护,使得更多的代码被写在了Controller中,这样Controller就显得非常 ...
- Android -------- MVC,MVP 和 MVVM 架构设计模式
MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用.它本身很容易理解,但是要讲清楚,它与衍生的 MVP 和 MVVM 架构的区别就不容易了. 一.MVC MV ...
随机推荐
- C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站
原文:C# 利用 HttpWebRequest 和 HttpWebResponse 模拟登录有验证码的网站 我们经常会碰到需要程序模拟登录一个网站,那如果网站需要填写验证码的要怎样模拟登录呢?这篇文章 ...
- Failed to issue method call: Unit mysql.service failed to load: No such file or directory解决的方式
Failed to issue method call: Unit mysql.service failed to load: No such file or directory解决的方式 作者:ch ...
- python进程池剖析(一)
python中两个常用来处理进程的模块分别是subprocess和multiprocessing,其中subprocess通常用于执行外部程序,比如一些第三方应用程序,而不是Python程序.如果需要 ...
- beanutils中WrapDynaBean
public class Emp { private String firstName="李"; private String lastName; public ...
- SZU:D89 The Settlers of Catan
Judge Info Memory Limit: 65536KB Case Time Limit: 3000MS Time Limit: 3000MS Judger: Number Only Judg ...
- Unity Container
Unity Container中的几种注册方式与示例 2013-12-08 22:43 by 小白哥哥, 22 阅读, 0 评论, 收藏, 编辑 1.实例注册 最简单的注册方式就是实例注册,Unity ...
- C/S应用升级更新完整解决方案
年末福利,C/S应用升级更新完整解决方案放送 程序员,工作累寿命短,大家应该学会分享,别浪费有限的生命与健康做重复的事情. C/S方式实现的应用有个升级更新功能是必需的,以前整过一个但是没考虑多套C/ ...
- Vijos1055 奶牛浴场(极大化思想求最大子矩形)
思路详见 王知昆<浅谈用极大化思想解决最大子矩形问题> 写得很详细(感谢~....) 因为不太会用递推,所以用了第一种方法,时间复杂度是O(n^2),n为枚举的点数,对付这题绰绰有余 思路 ...
- 记一次有趣的互联网事件及console.log~
寂寞的中国互联网又一次瘫痪了. 说是顶级域的根挂了,不知道是黑客还是某个实习生干挂的. 反正到现在还没有人来解释这件事. 先普及一下,为什么顶级域的根挂了全中国都挂了. 那是因为dns解析的特点是递归 ...
- 数组和Hash表
数组和Hash表 当显示多条结果时,存储在变量中非常智能,变量类型会自动转换为一个数组. 在下面的例子中,使用GetType()可以看到$a变量已经不是我们常见的string或int类型,而是Obje ...