概要

MVC架构,Model-View-Controller,如图一所示为一个典型的MVC设置。

图一: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中。

图二:MVVM.png
 

这样做可带来如下的益处:

  • 减少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作用如图三所示:

图三:MVVM ReactiveCocoa.png

如果想要深入了解ReactiveCocoa,可以看下ReactiveCocoa这篇文章。



[HMLY]11.MVVM架构的更多相关文章

  1. ReactiveCocoa常见操作方法介绍/MVVM架构思想

      1.ReactiveCocoa常见操作方法介绍. 1.1 ReactiveCocoa操作须知 所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中, ...

  2. MVVM架构~目录

    回到占占推荐博客索引 MVVM在概念上是真正将页面与数据逻辑分离的模式,在开发方式上,它是真正将前台代码开发者(JS+HTML)与后台代码开发者分离的模式(asp,asp.net,php,jsp).在 ...

  3. MVVM架构~Knockoutjs系列之验证机制的引入

    返回目录 对于Knockoutjs本身来说,没有提供验证模块,不过,有第三方的扩展,就像你为jquery库作extensions一样,这讲中我将介绍一个Knockout插件扩展,knockout.va ...

  4. MVVM架构~使用boxy和knockoutjs实现编辑功能

    返回目录 这个功能我认为非常有用,尤其在后台管理系统中,它对用户来说,使用体验这块非常不错,下面是它的截图

  5. MVVM架构的一次实践,重写iOS头条客户端

    前言: 一个iOS头条APP,使用MVVM架构实现,代码中有注释,封装了AFN网络请求,解媾代码,使用起来非常方便.用最经典的TableView展示,后续不断更新,喜欢就star或fork一下,有问题 ...

  6. MVVM架构~knockoutjs系列之表单添加(验证)与列表操作源码开放

    返回目录 本文章应该是knockoutjs系列的最后一篇了,前几篇中主要讲一些基础知识,这一讲主要是一个实际的例子,对于一个对象的添加与编辑功能的实现,并将项目源代码公开了,共大家一起学习! knoc ...

  7. WPF MVVM 架构 Step By Step(6)(把actions从view model解耦)

    到现在为止,我们创建了一个简单的MVVM的例子,包含了实现了的属性和命令.我们现在有这样一个包含了例如textbox类似的输入元素的视图,textbox用绑定来和view model联系,像点击but ...

  8. iOS MVVM架构总结

    为什么使用MVVM iOS中,我们使用的大部分都是MVC架构.虽然MVC的层次明确,但是由于功能日益的增加.代码的维护,使得更多的代码被写在了Controller中,这样Controller就显得非常 ...

  9. Android -------- MVC,MVP 和 MVVM 架构设计模式

    MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用.它本身很容易理解,但是要讲清楚,它与衍生的 MVP 和 MVVM 架构的区别就不容易了. 一.MVC MV ...

随机推荐

  1. EF分页问题探讨之 OrderBy

    EntityFramework 应用场景 最近被应用程序中页面加载慢的问题所折磨,看似容易的问题,其实并不容易(已经持续两天时间了),经过“侦查”,发现了两个“嫌疑犯”: EntityFramewor ...

  2. 代码审查 (Google牛人谈Code Review)

    代码审查 (Google牛人谈Code Review) 在上一篇博客里我暗示自己将不在为Google工作. 我还没有决定好去哪儿-有几个非常不错的工作机会让我选择.鉴于这段时间内我不受雇于任何公司,我 ...

  3. Smarty数学运算

    数学运算可以直接应用到变量 Example 3-5. math examples 例 3-5.数学运算的例子   {$foo+1} {$foo*$bar} {* some more complicat ...

  4. 话谈c#拷贝

    c#中类型分为值类型和引用类型,值类型对象赋值是本身就是赋的自身的一个副本,而引用类型赋值时则赋的是指向堆上的内存,假如我们不想赋这个地址而想将对象赋过去要怎么做呢?首先要知道拷贝分为浅表拷贝和深层拷 ...

  5. HttpClient的使用-爬虫学习(一)

    Apache真是伟大,为我们提供了HttpClient.jar,这个HttpClient是客户端的http通信实现库,这个类库的作用是接受和发送http报文,引进这个类库,我们对于http的操作会变得 ...

  6. vector cin

    vector<int>vec1,vec2; int ival; cout<<"Ender numbers for vector1(-1 to end):"& ...

  7. 如何将 Area 中的 Controller 放到独立的程序集?

    目录 背景如何将 Area 中的 Controller 放到独立的程序集?备注 背景返回目录 本文假设您已经熟悉了 ASP.NET MVC 的常规开发方式.执行模型和关键扩展点,这里主要说一下如何使用 ...

  8. BroadcastReceiver基础总结

    BroadcastReceiver基础总结 BroadcastReceiver是Android四大组件之一,主要负责接收系统或其他程序发出的广播,在开发中,通常用做事件驱动的起源,比如开机就要开启一个 ...

  9. java中除去字符串(String)中的换行字符(\r \n)

    有时在文本框中输入内容特别是粘贴内容时会出现一些换行符(\r\n),如下,在做字数验证或保存到数据库中时应过滤掉. str.replaceAll("\r|\n","&qu ...

  10. VS2010 下编译 cocos2d-x-2.1.4

    在VS2010 下编译 cocos2d-x-2.1.4   首先感谢 cocos2d-x 团队为我们做出这么好的跨平台框架,让我们这些码农省了很多时间,事半功倍. 里沃特最近在编译 win32 版本的 ...