1.MVVM之优雅地开发UITabelView2019

前言:

我是个偏瘦的程序猿,增肥是我的梦想,但自己写的项目中是用MVC的,Controller越来越臃肿,有时候维护起来,不方便。想着用MVVM来减肥。

 

正文

一、MVVM是什么?

在MVVM设计模式中,组件变成了Model-View-ViewModel。

MVVM有两个规则

  • View持有ViewModel的引用,反之没有
  • ViewModel持有Model的引用,反之没有

简单来说,View文件import只导入ViewModel.h头文件,ViewModel文件import只导入Model.h头文件,至于Model文件什么都不导入,就是简单的模型。

 

和MVC相比,表面看起来就是少了Controller,以及多了ViewModel.

实际开发中,UIViewControllerView往往是绑定在一起的,UIViewController可以当作一个重量级的View(负责界面切换等)。

不难看出,MVVM是对MVC的扩展,所以MVVM可以完美的兼容MVC。

对于一个界面来说,有时候View和ViewModel往往不止一个,MVVM也可以组合使用:

 

 


 

二、MVVM的优点和缺点

1.优点:在 iOS 开发中实践 MVVM 的话,通常会把大量原来放在 ViewController 里的视图逻辑和数据逻辑移到 ViewModel 里,从而有效的减轻了 ViewController 的负担。另外通过分离出来的 ViewModel 获得了更好的测试性,我们可以针对 ViewModel 来测试,解决了界面元素难于测试的问题。MVVM 通常还会和一个强大的绑定机制一同工作,一旦 ViewModel 所对应的 Model 发生变化时,ViewModel 的属性也会发生变化,而相对应的 View 也随即产生变化。

2.缺点:

1.MVVM 的学习成本和开发成本都很高。MVVM 是一个年轻的设计模式,大多数人对他的了解都不如 MVC 熟悉,基于绑定机制来进行编程需要一定的学习才能较好的上手。同时在 iOS 客户端开发中,并没有现成的绑定机制可以使用,要么使用 KVO,要么引入类似 ReactiveCocoa 这样的第三方库,使得学习成本和开发成本进一步提高。

2.数据绑定使 Debug 变得更难了。数据绑定使程序异常能快速的传递到其他位置,在界面上发现的 Bug 有可能是由 ViewModel 造成的,也有可能是由 Model 层造成的,传递链越长,对 Bug 的定位就越困难。

同时还必须指出的是,在传统的 MVVM 架构中,ViewModel 依然承载的大量的逻辑,包括业务逻辑,界面逻辑,数据存储和网络相关,使得 ViewModel 仍然有可能变得和 MVC 中 ViewController 一样臃肿。


 

 

三、优雅地开发UITabelView

model层

1.Person.h文件

#import <Foundation/Foundation.h>
 
@interface Person : NSObject
@property (copy, nonatomic) NSString * name;
@end

Person.m文件

#import "Person.h"

@implementation Person

@end

 


 

 

ViewModel层

CustomCellModel.h文件

#import <Foundation/Foundation.h>
#import "Person.h"//1.引入model的头文件

@protocol CellActionDispatchable <NSObject>//4.定义协议
@property (copy, nonatomic) NSString * selNameForDidSelected;
@end

@interface CustomCellModel : NSObject<CellActionDispatchable>//5.遵守s协议

@property (strong, nonatomic) Person * person;//2.定义属性

@property (copy, nonatomic) NSString * selNameForDidSelected;//6.实现协议

- (instancetype)initWithModel:(Person *)person;//3.定义对象方法
+ (NSArray*)queryData;//7.请求后台数据
@end

CustomCellModel.m文件

#import "CustomCellModel.h"
 
@implementation CustomCellModel
- (instancetype)initWithModel:(Person *)person{
    if (self = [super init]) {
        self.person = person;
 
        self.selNameForDidSelected = @"test";//标识要点击访问的方法名
       
    }
    return self;
}
+(NSArray *)queryData{
    //模拟请求后台返回的json数据,json转model数组
    Person *p = [[Person alloc]init];
    p.name = @"张三";
    
    Person *p2 = [[Person alloc]init];
    p2.name = @"李四";
    return  [NSArray arrayWithObjects:p,p2, nil];
}
@end

 


 

 

View层

CustomTableViewCell.h文件

#import <Foundation/Foundation.h>
#import "CustomCellModel.h"//1.引用viewModel层


@interface CustomTableViewCell : UITableViewCell
@property (strong, nonatomic) UILabel * nameLabel; //2.定义UI
 
@property (strong, nonatomic) CustomCellModel * cellModel;//3.定义属性

- (void)bindWithCellModel:(CustomCellModel *)cellModel;//4.定义对象方法,进行数据绑定用的
@end

CustomTableViewCell.m文件

#import "CustomTableViewCell.h"
 
@implementation CustomTableViewCell
- (void)bindWithCellModel:(CustomCellModel *)cellModel{
    self.cellModel = cellModel;
    self.nameLabel.text = cellModel.person.name;
}

//自定义TableViewCell 纯代码
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
 
        UILabel *label = [[UILabel alloc] init];
        label.frame = CGRectMake(16,17,72,20);
        
        [self addSubview:label];
        
        self.nameLabel = label;
 
       
    }
    return self;
}

@end

 


 

Controller类

TableViewController.h文件


#import <UIKit/UIKit.h>
 
@interface TableViewController : UITableViewController
@property (strong, nonatomic)NSArray *dataArray;
@end

TableViewController.m文件

 

 

#import "TableViewController.h"
#import "CustomTableViewCell.h"
#import "CustomCellModel.h" //1.引入viewModel


@implementation TableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
  
    self.dataArray = [CustomCellModel queryData];//2.请求数据
   
    [self.tableView registerClass:[CustomTableViewCell class] forCellReuseIdentifier:[CustomTableViewCell className]];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"CustomTableViewCell" forIndexPath:indexPath];
   
    Person * model = [self.dataArray objectAtIndex:indexPath.row];
 
    CustomCellModel * cellModel = [[CustomCellModel alloc] initWithModel:model];
   
    [cell bindWithCellModel:cellModel];//3.数据绑定
    return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
      [tableView deselectRowAtIndexPath:indexPath animated:true];
    
    id<CellActionDispatchable> cellModel =[[CustomCellModel alloc] initWithModel: [self.dataArray objectAtIndex:indexPath.row]];
 
    NSString * selName = cellModel.selNameForDidSelected;
 
    [self performSelector:NSSelectorFromString([selName stringByAppendingString:@":"]) withObject:indexPath afterDelay:0.0];//4.避免使用大量的if else去做判断
 
}

-(void)test:(NSIndexPath *)indexPath{
     DLog(@"Log=test%ld",indexPath.row);//5.调用相应的方法
}


@end

 

posted on 2019-05-17 16:16  cj2527  阅读(184)  评论(0)    收藏  举报

导航