MVVM架构

概要

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这篇文章。

备注:本文为读书笔记,主要参考了如下几篇文章:



文/NapoleonY(简书作者)
原文链接:http://www.jianshu.com/p/6e5dda137c7e
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值