美文网首页
实践MVVM设计模式

实践MVVM设计模式

作者: 灰灰的救赎 | 来源:发表于2016-11-26 09:16 被阅读9次

mvc模式的缺点。
1.c层(viewController层),代码冗余,不方便阅读。一般包括以下几点:
1)界面构建。
2)网络数据的请求和后续处理。
3)响应逻辑。比如对点击事件的处理、很多delegate方法。
4)数据源方法。比如常用的tableView会有datasource方法,其中数cellForRowAtIndexpath最为典型,其中数据展示前的代码也是非常的多。
举个例子:在使用tableView时,section、row的判断很头疼,点击时间的if 、switch判断更加让人烦躁。如:

c层的逻辑处理.png

不加注释的行为简直受不了!
其次,代码不够灵活,后期难以维护。想要增加、删除的功能时,不仅要修改数据源(self.storeArray)中的数据,还要修改tableView中返回的section,row的数量,还需要修改cellForRow中,view的赋值,和对cell点击事件的处理,感觉无从下手。
最后,c层代码太多,仅仅一个界面就达到了1,2千行左右的代码,寻找很不方便。(尤其是不加注释!)
那么接下来,我们主要介绍下传说的MVVM模式,即Model +View +ViewModel。其实相比于MVC,重点在于ViewModel,我的理解就是,将我们对传统的Model进行继承和重用。下面通过一个例子来说说。


界面.png

首先,我们可以将界面根据cell类型,去分几大类。如,该界面中,第一类"地址"cell,第二类"药店"cell,第三类''其他''cell(都的左侧、右侧都是文本型)。
这样我们就可以就只需要3个model,来分别储存在3中cell的数据。但是这3中model也有很多通用的数据,如cell的种类,cell的高度,cell是否要显示,cell是否能点击等等。这就需要一个基类,来存放这些通用的属性。上述的3个model来继承这个基类,来实现model的重用。
如:我们通过建立SubmitOrderBaseModel为基类

@interfaceSubmitOrderBaseModel :NSObject
/**
cell高度
*/
@property(nonatomic,assign)CGFloatcellHeight;
/**
cell类型
*/
@property(nonatomic,copy)NSString* type;
/**
model名称
*/
@property(nonatomic,copy)NSString* title;
/**
是否显示
*/
@property(nonatomic,assign)BOOLisShow;
/**
是否能点击
*/
@property(nonatomic,assign)BOOLisSelected;
/**
子model
*/
@property(nonatomic,strong)NSMutableArray*models;
@end

一定要加注释!
"地址"cell,SubmitOrderAddressModel,继承SubmitOrderBaseModel

@interface SubmitOrderAddressModel : SubmitOrderBaseModel

@end

"药店"cell,SubmitOrderShopModel,继承SubmitOrderBaseModel

@interface SubmitOrderShopModel : SubmitOrderBaseModel

@end

其他cell,SubMitOrderNormalModel,继承SubmitOrderBaseModel

@interface SubMitOrderNormalModel :SubmitOrderBaseModel

/**
 右侧文字输入方向
 */
@property(nonatomic,strong)NSString *rightTextAlignment;

/**
 右侧字体颜色
 */
@property(nonatomic,strong)UIColor *rightColor;
@end

''其他''cell中又有写微小的区别,比如右侧文本的颜色和输入方向,这是''其他''cell中的独有属性。
好,现在我们可以在ViewController中,根据界面的需求来处理数据。在上面的''界面''中,我们分析了需要3种model来储存数据,但是他根据业务逻辑分了6个(其实是大于6个,一个药店一个section)section。这样的话,可以根据section的个数来处理数据。创建个一个大数组(orderTypeArray),其中储存了我们所要展示的所有数据,他的个数就是section的个数。
在处理数据时,我遇到的问题是,“其他”cell,type都是一种属性,你要在models属性中添加要展示的cell数据,封装成一种数据格式,比如我封装成字典以"NAME"为key,方便赋值时使用。
整理后的数组大概是这个样子的:


处理后的数据.png

现在拿到数组后,就可以去赋值了。首先我们把tableView的delegate拿出来,独立成一个类,然后在tableView设置代理和数据源时,绑定在个类。

    _delegate = [[SubmitOrderTableViewDelegate alloc] init]; 
    _mainTableView.delegate =_delegate;
    _mainTableView.dataSource =_delegate;

要记得在SubmitOrderTableViewDelegate.h中遵守UITableViewDataSource,UITableViewDelegate。
然后我们就可以在SubmitOrderTableViewDelegate.m中实现要展示的数据了。
1) 在numberOfSectionsInTableView方法中,返回当然是数组(orderTypeArray)中model的个数了。

    return _orderTypeArray.count;

2)在numberOfRowsInSection方法中,返回的是每个model中models中的对象个数。

    SubmitOrderBaseModel *model =_orderTypeArray[section];
    
    if ([model.type isEqualToString:@"OrderAddressTableViewCell"] || [model.type isEqualToString:@"GoodsShopTableViewCell"] )//地址、药品只返回1
    {
        return 1;
    }
    return model.models.count;

3)在heightForRowAtIndexPath方法中,返回的是我们model.cellHeight参数。

    SubmitOrderBaseModel *model =_orderTypeArray[indexPath.section];
    
    CGFloat height =0;
    
    if (!model.cellHeight)
    {
        SubmitOrderBaseModel *subModel =   model.models[indexPath.row];
        
        if (subModel.isShow)                //是否显示
        {
            height = subModel.cellHeight;
        }
        else
        {
            height = 0;
        }
    }
    else
    {
        height = model.cellHeight;          //地址、药品cell
    }
    return height;

这里需要注意的是"是否显示cell"这个属性。
现在来到关键的cellForRowAtIndexPath方法。

    NSString *cellType =@"";
    SubmitOrderBaseModel *data = _orderTypeArray[indexPath.section];
    SubmitOrderBaseModel *subData = data.models[indexPath.row];
    if (!data.type) //地址、药品Type
    {
        cellType = subData.type;
    }
    else
    {
        cellType = data.type;
    }
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellType];
    if (cell ==nil)
    {
        cell = [[NSClassFromString(cellType) alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellType];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

首先根据cellType来创建cell。然后根据cell的类型(也就是cellType的类型)来为指定的cell赋值。
比如,当前cell是''地址''cell

     if ([cell isKindOfClass:[OrderAddressTableViewCell class]])
     {
       ((OrderAddressTableViewCell *)cell).accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        
        ((OrderAddressTableViewCell *)cell).nameLabel.text = ((NSDictionary*)subData)[@"RECEIVER"];
        ((OrderAddressTableViewCell *)cell).phoneLabel.text = ((NSDictionary*)subData)[@"CONTACTPHONE"];
        ((OrderAddressTableViewCell *)cell).addressLabel.text = ((NSDictionary*)subData)[@"ADDRESS"];
    }

这些都是简单的为控件赋值。
在比如,“其他”cell

     if ([cell isKindOfClass:[ActionCell class]])
      {
        if (((SubMitOrderNormalModel*)subData).isShow)
        {
            ((ActionCell *)cell).hidden = NO;
        }
        else
        {
            ((ActionCell *)cell).hidden = YES;
        }
        if (((SubMitOrderNormalModel*)subData).isSelected)
        {
            ((ActionCell *)cell).accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        }
        else
        {
            ((ActionCell *)cell).accessoryType = UITableViewCellAccessoryNone;
        }
        
        ((ActionCell *)cell).titleLab.text = ((SubMitOrderNormalModel*)subData).title;          //标题
        
        NSDictionary *infoDic =((SubMitOrderNormalModel*)subData).models[0];                    //详情信息
        ((ActionCell *)cell).actionLab.text = infoDic[@"NAME"];
        
        if (((SubMitOrderNormalModel*)subData).rightColor)                                      //详情字体颜色
        {
            ((ActionCell *)cell).actionLab.textColor= ((SubMitOrderNormalModel*)subData).rightColor;
        }
        else
        {
            ((ActionCell *)cell).actionLab.textColor= [UIColor blackColor];
        }
        
        if ([((SubMitOrderNormalModel*)subData).rightTextAlignment isEqualToString:@"left"])    //详情信息输入方向
        {
            ((ActionCell *)cell).actionLab.textAlignment = NSTextAlignmentLeft;
        }
        else
        {
            ((ActionCell *)cell).actionLab.textAlignment = NSTextAlignmentRight;
        }

到这里可以看出,我们并没有通过 section和row的顺序来为控件赋值,而是通过我们传入的数据来映射到特定的cell。
然后是点击事件,这里我们需要把点击的indexPath,和model传出去进行处理就可以了。

到这里,大家可能会对MVVM有了一定的认识,这种通过只对数据源处理,就可以展示我们界面的内容。极大的增加了代码的灵活性,在以后维护时,我们要想改变cell的展示顺序,或者新增、删除某个cell,我们都可以通过对数据源(即orderTypeArray)的存储顺序,增加、删除某条数据就可以了。

相关文章

  • iOS MVVM架构总结

    参考:iOS 中MVC设计模式iOS MVVM架构iOS MVVM-框架介绍iOS 架构模式MVVM的实践总结iO...

  • 实践MVVM设计模式

    mvc模式的缺点。1.c层(viewController层),代码冗余,不方便阅读。一般包括以下几点:1)界面构建...

  • iOS - MVVM模式设计实践

    工程项目中 Controller越来约臃肿,业务和View层耦合越来约严重,如何给Controller减减负迫在眉...

  • Vue快速入门

    MVVM模式 什么是MVVM模式? MVVM(Model-View-ViewModel)是一种软件架构设计模式,由...

  • MVVM设计模式

    MVVM设计模式 在介绍MVVM设计模式之前我们先介绍一下DataBinding DataBinding,2015...

  • vue面试问题

    1.MVVM模式和MVC模式 MVVM模式是Model-View-ViewModel的缩写。MVVM是一种设计...

  • 关于 MVVM 设计模式

    本文主要浅析传统 MVP 设计模式与先进流行的 MVVM 设计模式的一些区别,以及简要分析 MVVM 设计模式的优...

  • 浅谈MVVM的好处

    最近一个月一直在寻找MVVM在我项目中的最佳实践 发现MVVM设计模式确实很棒,当然MVVM和MVP其实是差不多的...

  • iOS 设计模式 一

    设计模式随记 系统架构模式 1. MVC - MVVM - MVP - MVVM、MVC协调版 MVC :...

  • MVVM设计模式在Android编程中的应用

    MVVM设计模式在Android编程中的应用 大家好,这一期呢,我们来看一下mvvm的设计模式。 Mvvm的意思是...

网友评论

      本文标题:实践MVVM设计模式

      本文链接:https://www.haomeiwen.com/subject/phowpttx.html