iOS之MVVM架构

什么是MVVM

 

MVVM就是在MVC的基础上分离出业务处理的逻辑到viewModel层,即:
model层,API请求的原始数据

 

view层,视图展示,由viewController来控制

 

 

viewModel层,负责业务处理和数据转化,简单来说,就是API请求完数据,解析成model,之后在viewModel中转化成能够直接被视图层使用的数据,交付给展示页面。

 

 

 


Model层是少不了的了,我们得有东西充当DTO(数据传输对象),当然,用字典也是可以的,编程么,要灵活一些。Model层是比较薄的一层,如果学过Java的小伙伴的话,对JavaBean应该不陌生吧。

ViewModel层,就是View和Model层的粘合剂,他是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他各种各样的代码的极好的地方。说白了,就是把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。

View层,就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。

view-model 一词的确不能充分表达我们的意图. 一个更好的术语可能是 “View Coordinator”(感谢Dave Lee提的这个 “View Coordinator” 术语, 真是个好点子)。你可以认为它就像是电视新闻主播背后的研究人员和作家团队。它从必要的资源(数据库, 网络服务调用, 等)中获取原始数据, 运用逻辑, 并处理成 view (controller) 的展示数据. 它(通常通过属性)暴露给视图控制器需要知道的仅关于显示视图工作的信息(理想地你不会暴漏你的 data-model 对象)。 它还负责对上游数据的修改(比如更新模型/数据库, API POST 调用)。

MVVM是基于胖Model的架构思路建立的,然后在胖Model中拆出两部分:Model和ViewModel。ViewModel本质上算是Model层(因为是胖Model里面分出来的一部分),所以View并不适合直接持有ViewModel,因为ViewModel有可能并不是只服务于特定的一个View,使用更加松散的绑定关系能够降低ViewModel和View之间的耦合度。

 

 

  • ViewController 尽量不涉及业务逻辑,让 ViewModel 去做这些事情。
  • ViewController 只是一个中间人,接收 View 的事件、调用 ViewModel 的方法、响应 ViewModel 的变化。
  • ViewModel 不能包含 View,不然就跟 View 产生了耦合,不方便复用和测试。
  • ViewModel 之间可以有依赖。
  • ViewModel 避免过于臃肿,不然维护起来也是个问题。

 

MVVM 并不复杂,跟 MVC 也是兼容的,只是多了一个 ViewModel 层,但就是这么一个小改动,就能让代码变得更加容易阅读和维护,不妨试一下吧。

 

怎么实现MVVM呢接下来我将通过代码来演示一下我的具体实现过程。

 

model层

在这里我们用JSONModel来解析,比如一个商品列表的model长这样:

 

#import <JSONModel/JSONModel.h>

@protocol ProductListModel <NSObject>
@end


@interface ProductListModel : JSONModel
@property (nonatomic, copy) NSString *imgUrl;
@property (nonatomic, copy) NSString *productId;
@property (nonatomic, copy) NSString *productName;
@property (nonatomic, copy) NSString *refPrice;


@end

 这是我们的数据原型,API返回的数据通过JSONModel解析完成后的原始数据存在这里。

 

viewModel 层 

viewModel层是我们处理业务逻辑的核心层,在这里我们需要发起网络请求(如果网络请求较多,可以抽出来,只在ViewModel里调用)、解析数据、转换数据给前端。

- (void)startLoadProductListWithPage:(NSInteger)page {


  __weak typeof(self) weakSelf = self;


  [NetWorkManager GET:self.baseURL
                   parameters:parameters
                        success:^(NSURLSessionDataTask *task, id responseObject) {


    __strong typeof(weakSelf) strongSelf = weakSelf;
    ...


    NSDictionary *resultDic = responseObject[@"rp_result"];
    NSError *error = nil;
    ProductListModel *model = [[ProductListModel alloc] initWithDictionary:resultDic error:&error]; 


    if (error) {
      ...
    }


    [strongSelf calProductLists:model.productlist];
    if (strangles.delegate ...) {
       ...
    }


  } failure:^(NSURLSessionDataTask *task, NSError *error) {
    ...
  }];
}


- (void)calProductLists:(NSArray *)productLists {

  for (NSInteger i = 0; i < productLists.count; ++i) {
    ProductListModel *model = productLists[i];
    ProductListItem *item = [[ProductListItem alloc] init];
    item.productId = model.productId;
    item.productName = model.productName;
    item.productPrice = [NSString stringWithFormat:@"¥ %@", model.refPrice];
    item.productImgURL = [Utils convertToRealUrl:model.imgUrl ofsize:300];
    [self.productLists addObject:item];
  }

}

在viewModel中将API返回的数据解析成model,并将model转化成可供view层直接使用的item,将item交付给前端使用。

经过viewModel转化之后的数据item由viewModel保存,与数据相关的处理都将在viewModel中处理。viewModel返回给view层的接口长这样:

 

@interface ProductListViewModel (CollectionViewDataSource)

- (NSInteger)m_numberOfItemsInSection:(NSInteger)section;
- (ProductListItem *)m_itemForIndexPath:(NSIndexPath *)indexPath;

@end

 

 

view层

 

 

view层是由viewController控制的。view层只做展示,不做业务处理。view层的数据由viewModel提供。view层看起来是这样的:

@implementation ProductListViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor whiteColor];

  [self initial];
  [self setupViewModel];
  [self setupSubViews];

  [self.viewModel startLoadProductListWithPage:_currentPage];
}


- (void)initial {
  ...
  self.currentPage = 1;
}


- (void)setupViewModel {
  self.viewModel = [[ProductListViewModel alloc] init];
  _viewModel.delegate = self;
}


- (void)setupSubViews {
  ...
  [self setupCollectionView];
  ...
}


- (void)setupCollectionView {
   ...
}


#pragma mark - UICollectionView Delegate & Datosource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  return [self.viewModel m_numberOfItemsInSection:section];
}


- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {


  ProductListItem *item = [self.viewModel m_itemForIndexPath:indexPath];
  ProductListCollectionViewCell *cell = (ProductListCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:kProductListCollectionViewCellId forIndexPath:indexPath];
  [cell setupWithItem:item];


  return cell;
}

 

 

MVVM的缺点

转化过程的成本很大,主要在于:

1、数组内容的转化成本较高:数组里面每项都要转化成Item对象,如果Item对象中还有类似数组,就很头疼。
2、转化之后的数据在大部分情况是不能直接被展示的,为了能够被展示,还需要第二次转化。
3、只有在API返回的数据高度标准化时,这些对象原型(Item)的可复用程度才高,否则容易出现类型爆炸,提高维护成本。
4、调试时通过对象原型查看数据内容不如直接通过NSDictionary/NSArray直观。
5、同一API的数据被不同View展示时,难以控制数据转化的代码,它们有可能会散落在任何需要的地方。
针对这些缺点,也提出了相应的解决方法,即用一个类似reformer的对象进行数据过滤,根据不同的reformer对象过滤出不同的数据。

 

 

 

 

 

 

另外,这篇文章说得也很浅显易懂!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值