内容简介:一直在做一线的业务开发工作,每天接触业务线,时间久了就开始思考如何能优化架构、提高维护效率,于是就接触了MVVM的出现主要是为了解决在开发过程中Controller越来越庞大的问题,变得难以维护,所以MVVM把数据加工的任务从Controller中解放了出来,使得Controller只需要专注于具体业务的工作,ViewModel则去负责数据加工并通过各种通知机制让View响应ViewModel的改变。我最开始听说
一直在做一线的业务开发工作,每天接触业务线,时间久了就开始思考如何能优化架构、提高维护效率,于是就接触了 MVVM
。
MVVM的出现主要是为了解决在开发过程中Controller越来越庞大的问题,变得难以维护,所以MVVM把数据加工的任务从Controller中解放了出来,使得Controller只需要专注于具体业务的工作,ViewModel则去负责数据加工并通过各种通知机制让View响应ViewModel的改变。
还有一个让人很容易忽略的问题,大部分国内外资料阐述MVVM的时候都是这样排布的:Model - View - ViewModel , 客观上造成了MVVM不需要Controller的错觉,可事实上是这样的么? 复制代码
分析使用逻辑
ViewModel部分
我最开始听说 MVVM 的时候是一脸懵逼的,因为我在这几个子母中间没有看到Controller的影子,我对于Controller的使用逻辑一无所知。但是直觉告诉我,Controller依然还是不可获取的一部分,至少操作View的时候还是会需要。 ViewModel 这个单词本身也让我产生了困扰,这个术语本身可能导致混乱,因为它是我们已经知道的两个术语的混搭,不知道这个结构更偏向于 View 和 Model 哪一边。
当我查阅资料的时候,网上大部分的MVVM的表述都是 View <-> ViewModel <-> Model
,都是在说ViewModel支持数据的双向绑定,表述模糊,我还是不能完全明白 ViewModel
的真正用处和存在意义。
比如像下面的说法:
它将model信息转变为view需要的信息,同时还将命令从view传递到model。View与Model通过ViewModel实现双向绑定。
我的着眼点放在了上面的第一句话上,即“ 它将model信息转变为view信息,同时还将命令从view传递到model
”。当我进一步去理解 ViewModel 的作用的时候,我发现ViewModel更应该被称呼作为“ View与Model中间的观察协调器 ”,它主要作用是拿到原始的数据,根据具体业务逻辑需要进行处理,之后将处理好的东西塞到View中去,其职责之一是静态模型,表示View显示自身所需的数据,这使View具有更清晰定义的任务,即呈现视图模型提供的数据,总结为一句话就是 与View直接对应的Model,逻辑上是属于Model层 。
Controller部分
那么Controller的作用呢?
MVVM其实是是基于胖Model的架构思路建立的,然后在胖Model中拆出两部分:Model和ViewModel。 即 MVC -> 胖Model -> Model+ ViewModel
这个演化过程。
和上文分析一致,ViewModel本质上算是Model层(作为与View显示自己所直接对应的Model),所以View并不适合直接持有ViewModel,反之则可以。因为ViewModel有可能并不是一定只服务于特定的一个View,使用更加松散的绑定关系能够降低ViewModel和View之间的耦合度。现在可以说,Controller唯一关注的是使用来自ViewModel的数据配置和管理各种View,Controller的作用就是负责控制 View 和 ViewModel 的绑定和调用关系,Controller 不需要 了解Web服务调用,Core Data,model对象等,这些都是可以丢给ViewModel去操作。
以下2张图或许有更直观的感受:
图片来源: www.sprynthesis.com/2014/12/06/…
我来解释一下图片指代的意思:
- MVVM中的View本质上代指的是View和Controller两部分结构。
- 而MVVM中的ViewModel则是抽离了Controller的一些业务出来组成了ViewModel,同时Controller的工作量减小了很多。
- 当Controller抽离出来ViewModel之后,MVVM中View也可以区分为View和Controller两部分之后,就成了第二张图 MVCVM 的结构,Controller的代销也就变小了。
所以说,归根结底 MVVM 更应该被形容为 View <-> C <-> ViewModel <-> Model
,即 MVCVM 的设计模式,这样就很清晰的解释了Controller的位置以及作用。
进一步梳理
通过以上,我们可以逻辑上得出,Controller应该是持有了ViewModel和View,并对二者进行判断和匹配操作。ViewModel有可能并不是一定只服务于特定的一个View,Controller当中也会有很多的View,所以,同一个Controller可能持有很多个ViewModel,以此来实现不同的业务逻辑控制多重的View。
Controller唯一关注的是使用来自ViewModel的数据配置和管理各种View,并让ViewModel知道何时发生需要更改上游数据的相关用户输入。 Controller不需要知道网络请求、数据库操作以及Model等,这样就让Controller更集中的去处理具体的业务逻辑。
图片来源: www.sprynthesis.com/2014/12/06/…
- Controller:负责View和ViewModel之间的调配和绑定关系,执行业务逻辑。
- View:展示UI,接受Action。
- ViewModel:网络请求,数据加工,数据持有。
- Model:原始数据。
大致会形成以下调用关系:
代码演示
废话不多说,先上Demo: github.com/derekhuangx…
下面我会摘出部分重要代码,给大家讲解一下具体的逻辑
MarshalModel
MarshalModel.h @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger lessonCount; 复制代码
Model相对来说就比较简单了,用来储存原始数据。
MarshalViewModel
MarshalViewModel.h @interface MarshalViewModel : NSObject @property (nonatomic, strong, readonly) NSString *name; @property (nonatomic, strong, readonly) NSString *detailTextString; @property (nonatomic, assign, readonly) UITableViewCellAccessoryType cellType; - (instancetype)initWithModel:(MarshalModel *)model; @end MarshalViewModel.m @interface MarshalViewModel () @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *detailTextString; @property (nonatomic, assign) UITableViewCellAccessoryType cellType; @end @implementation MarshalViewModel //依赖注入 - (instancetype)initWithModel:(MarshalModel *)model ; { if (self = [super init]) { self.name = model.name; if (model.lessonCount > 35) { self.detailTextString = @"多于30门课程"; self.cellType = UITableViewCellAccessoryDetailDisclosureButton; } else { self.detailTextString = [NSString stringWithFormat:@"课程数量:%ld", (long)model.lessonCount]; self.cellType = UITableViewCellAccessoryNone; } } return self; } 复制代码
- ViewModel的.h文件中,只放置了初始化的代码,执行Model数据的注入,另外提供了向View暴露的接口,这部分要注意了,要加上
readonly
的标示符,当然也可以用GET
方法代替,这样可以避免View修改ViewModel中的数据,保证 数据从一条线注入,处理之后,从另一条线取出 。 - ViewModel的.m文件,可以说是对于原始数据的处理操作,这里基本上就是对于原始数据转化为View需要数据的处理。当然,大家也可以根据自己的需要增加Cache或者数据库等的操作,也可以增加网络数据获取的操作。
MarshalCell
MarshalCell.h @interface MarshalCell : UITableViewCell @property (nonatomic, strong) MarshalViewModel *viewModel; @end MarshalCell.m - (void)setViewModel:(MarshalViewModel *)viewModel { _viewModel = viewModel; self.textLabel.text = viewModel.name; self.detailTextLabel.text = viewModel.detailTextString; self.accessoryType = viewModel.cellType; } 复制代码
我只把.m文件中的 SET
方法给大家展示出来了,我觉得就可以说明问题,ViewModel中提供了View需要的一切处理好的关键要素,那么View就会变得非常扁平,只需要处理点击这种的Action事件,并且传递给Controller即可,不需要关注原始数据转换的具体业务逻辑。
HomeViewController
HomeViewController.m @interface HomeViewController () @property (nonatomic, strong) NSMutableArray <MarshalViewModel *>*viewModels; @end - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MarshalCell *cell = [[MarshalCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: kMarshalCellIdentifier]; cell.viewModel = self.viewModels[indexPath.row]; return cell; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.viewModels.count; } - (void)getData { [[MarshalService shareInstance]fetchDataCompletion:^(NSArray<MarshalModel *> * _Nonnull data) { self.viewModels = [self viewModelsWithDatas:[data mutableCopy]]; dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); } failure:^(NSError * _Nonnull error) { NSLog(@"Failed to fetch courses:%@", error); }]; } 复制代码
大家可以看到,我用了 数组 来储存的ViewModel,原因是因为每个Cell所对应的的数据不一致导致UI展示不一致,所以每个Cell要有一个自己的ViewModel来填充自己UI数据。这就进一步印证了上面说的, ViewModel本质仍然是Model层 。
疑问点(不定期更新)
1、为什么View没有.h接口的可读处理,而ViewModel中要有?
在ViewModel中数据单向注入,之后会有数据根据业务逻辑处理,之后向View提供数据接口,为了保证数据不会被污染,所以增加了`readonly`的标示符,而View中则不需要以上的逻辑。 复制代码
2、当点击某个Cell的某部分之后,如何向后传值?
1.Controller找到对应的ViewModel,ViewModel作为Mother ViewModel,替代Controller做一个脏活,去生成相对应的Child ViewModel。 2.ViewModel将Child ViewModel返回给Controller。 3.Controller利用Child ViewModel生成下一页面的Controller,执行跳转操作。 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
指数型组织
萨利姆•伊斯梅尔 (Salim Ismail)、迈克尔•马隆 (Michael S. Malone)、尤里•范吉斯特 (Yuri van Geest) / 苏健 / 浙江人民出版社 / 2015-8-1 / CNY 69.90
《指数型组织》是一本指数级时代企业行动手册。作者奇点大学创始执行理事萨利姆·伊斯梅尔归纳了指数型组织的11个强大属性,并提出了建立指数型组织的12个关键步骤。通过自己创建的一套“指数商”测试题,伊斯梅尔还测量出了指数型组织世界100强。 为什么小米、海尔和阿里巴巴能进入“指数型组织世界100强”名单?“独角兽”Uber、Airbnb、谷歌等知名企业是如何指数化自己的组织的? 未......一起来看看 《指数型组织》 这本书的介绍吧!