转载

使用MVVM减少控制器代码实战(减少56%)

使用MVVM减少控制器代码实战(减少56%)

减少比例= (360(原来的行数)-159(瘦身后的行数))/360 = 56%

父类MVC 和MVVM 前后基本不动

父类主要完成如下三个功能:

  • 功能:MJRefrsh +上拉下拉没有更多数据,封装到父类的控制器 子类调用3行代码增加所有刷新功能

  • 网络失败:显示网络错误的链接,写在父类子类调用一行代码就可

  • 加载数据完成,列表中没有数据提示View,比如购买界面,没有购买记录,写在父类子类一行代码调用

瘦身思路(总的代码量增加了30多行,但是控制器更清爽了)

使用MVVM减少控制器代码实战(减少56%)

  • 网络前网络请求函数是这样的

瘦身结果

使用MVVM减少控制器代码实战(减少56%)

瘦身具体实现

1)网络请求移到ViewModel

以前网络代码直接写在控制器中,如下所示

- (void)loadDataForCaseDeatailMsg:(NSString*)caseManageId{    NSMutableDictionary *dict = createMutDict;     [dict setObject:@"case-info" forKey:@"method"];     [dict setObject:caseManageId forKey:@"caseManageId"];     [QTFHttpTool    requestPara:dict                         needHud:YES                         hudView:self.view                  loadingHudText:nil                    errorHudText:nil                          sucess:^(NSDictionary *json) {                                                       BOOL success = (BOOL)[json[@"success"] boolValue];                                                       if(success){                                  QTCaseDetailModel *caseDetailModel = [[QTCaseDetailModel alloc]init];                                  caseDetailModel.expertId = json[@"expertId"];                                  caseDetailModel.userName = json[@"userName"];                                  caseDetailModel.data = [QTCaseDetailMsgModel objectArrayWithKeyValuesArray:json[@"data"]];                                  [self gotoChatViewController:caseDetailModel];                               }                          }failur:^(NSError *error) {                           }]; }
  • MVVM封装后控制器中的网络请求是这样的,控制器只取需要的东西,如下所示,不关心一些无关的细节,细节移到ViewModel中,5行搞定了网络请求获取网络数据,还算精简吧!

- (void)loadDataForCaseDeatailMsg:(NSString*)caseManageId{     [QTCaseDetailViewModel caseDetailhudView:self.view caseManageId:caseManageId getDataSuccess:^(id item, NSInteger totalPage) {         [self gotoChatViewController:item];     } getDataFailure:^(NSError *error) {}]; }

具体实现在viewModle中,viewModel添加hud,完成字典转模型,对后台做错误处理,显示错误(部分工作在我自己封装的底层网络请求实现的)

+ (void)caseDetailhudView:(UIView*)hudView caseManageId:(NSString*)caseManageId getDataSuccess:(GetDataAllSuccessBlock)success getDataFailure:(GetDataFailureBlock)failure{     NSMutableDictionary *dict = createMutDict;     [dict setObject:@"case-info" forKey:@"method"];     [dict setObject:caseManageId forKey:@"caseManageId"];     [QTFHttpTool    requestPara:dict                         needHud:YES                         hudView:hudView                  loadingHudText:nil                    errorHudText:nil                          sucess:^(NSDictionary *json) {                              BOOL success1 = (BOOL)[json[@"success"] boolValue];                             if(success1){                                  QTCaseDetailModel *caseDetailModel = [[QTCaseDetailModel alloc]init];                                 caseDetailModel.expertId = json[@"expertId"];                                 caseDetailModel.userName = json[@"userName"];                                 caseDetailModel.data = [QTCaseDetailMsgModel objectArrayWithKeyValuesArray:json[@"data"]];                                  success(caseDetailModel,1);                              }                          }failur:^(NSError *error) {                           }];  }
  • 将网络请求部分工作移到Viewmodel中,本控制器有三个网络请求 这样节省代码量很可观

2) datasource,以前直接写在控制机器中,现在写到dataSource 文件中,控制器中调用dataSource这个类

/*  本类作用:用以处理TableView以及CollectionView的数据源  */#import @import UIKit;// 用于配置当前Cell的数据// id cell表示什么类型的Cell// id item表示什么类型的模型对象typedef void (^TableViewCellConfigureBlock)(id cell, id item);@interface QTArrayDataSource : NSObject // 参数1:用以数据源的控制,主要是通过改数组来控制当前tableView或者collectionView显示Cell的数量// 参数2:当前需要显示的cell的重用标示// 参数3:用以配置当前cell数据的block- (id)initWithItems:(NSArray *)anItems      cellIdentifier:(NSString *)aCellIdentifier  configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;// 通过indexPath来获取当前具体的某一个对象- (id)itemAtIndexPath:(NSIndexPath *)indexPath;@end
#import "QTArrayDataSource.h"#import "QTSpecialCaseCell.h"@interface QTArrayDataSource ()// 当前数据数组@property (nonatomic, strong) NSArray *items;// 当前cell重用标示@property (nonatomic, copy) NSString *cellIdentifier;// 当前配置cell的block@property (nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;@end@implementation QTArrayDataSource- (id)init {    return nil; }  - (id)initWithItems:(NSArray *)anItems      cellIdentifier:(NSString *)aCellIdentifier  configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock {    self = [super init];    if (self) {         _items = anItems;         _cellIdentifier = aCellIdentifier;         _configureCellBlock = [aConfigureCellBlock copy];     }    return self; }  - (id)itemAtIndexPath:(NSIndexPath *)indexPath {    return self.items[(NSUInteger)indexPath.row]; }#pragma mark UITableViewDataSource- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return self.items.count; }  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier                                                             forIndexPath:indexPath];    // 获取当前某一行的对象     id item = [self itemAtIndexPath:indexPath];    // 通过调用该block配置当前cell显示的内容     self.configureCellBlock(cell, item);    return cell; }#pragma mark UICollectionDataSource- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return self.items.count; }  - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {     QTSpecialCaseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:self.cellIdentifier                                                                            forIndexPath:indexPath];    // 获取当前某一行的对象      id item = [self itemAtIndexPath:indexPath];    // 通过调用该block配置当前cell显示的内容     self.configureCellBlock(cell, item);    return cell; }@end

3)  viewdidload代码中, 以协议的方式加载数据源

TableViewCellConfigureBlock configureCell = ^(QTSpecialCaseCell                                             *cell, id data) {         [cell configureForCell:data];     };     [_collectionView registerClass:[QTSpecialCaseCell class] forCellWithReuseIdentifier:CellIdentify];     self.arrayDataSource = [[QTArrayDataSource alloc]                                 initWithItems:self.data    cellIdentifier:CellIdentify     configureCellBlock:configureCell];         self.collectionView.dataSource = self.arrayDataSource;         self.collectionView.delegate = self;     [self refreshOneCreateCollectionView:_collectionView methodSelStr:@"loadData"];

4) 本文的待讨论的部分

  • 代理方法没有剥离出来,如果剥离出来,控制器进一步减少到120行左右,代理剥离有点麻烦,感觉没有必要

  • 创建collectionView 的代码没剥离,剥离出来可以再减少20行左右,也参考一些别人的文章,目前觉得就这样了,没必要的

  • 也参考了一些别人的代码:如何写好一个UITableView
    如何正确的写好一个UITableView,写的也很高大上,感觉各种继承,真的很复杂耶

使用MVVM减少控制器代码实战(减少56%)

  • 代码 不能过度封装,也不能不封装

有人对我的网络请求比较感兴趣,我的网络请求,针对公司的后台数据结构做了封装,hud 也封装到网络请求中了。

正文到此结束
Loading...