从MVP到MVVM

栏目: IOS · 发布时间: 4年前

内容简介:通过上篇文章,我们了解到利用mvp可以对mvc的c层瘦身,并使得层次分明,且网络请求变得通用。那就已经很完美了,那么mvvm是用来干嘛的呢。对于mvvm它是用来描述数据和视图的关系的。我们开发过程中常常发现数据变化会导致视图的变化,如一个列表,当没有数据的时候要展示空界面,当有数据的时候要展示对应条数的列表界面。在比如当网络请求回来的列表中的一个为已点赞数据,那么界面的相应视图就要显示红心其他都为灰心。以上示例都反应了数据和视图的这种绑定关系,并且数据一变化视图就要相应的进行变化,也就是所谓的数据驱动。

通过上篇文章,我们了解到利用mvp可以对mvc的c层瘦身,并使得层次分明,且网络请求变得通用。那就已经很完美了,那么mvvm是用来干嘛的呢。

对于mvvm它是用来描述数据和视图的关系的。我们开发过程中常常发现数据变化会导致视图的变化,如一个列表,当没有数据的时候要展示空界面,当有数据的时候要展示对应条数的列表界面。在比如当网络请求回来的列表中的一个为已点赞数据,那么界面的相应视图就要显示红心其他都为灰心。

以上示例都反应了数据和视图的这种绑定关系,并且数据一变化视图就要相应的进行变化,也就是所谓的数据驱动。

以上介绍在说明数据驱动视图这件事,这和mvc,mvp是不同的,导致了编码思想也不同。

数据一变化视图就要变化,也就是要监听数据的变化,这可以利用kvo。但是苹果中的kvo用起来很麻烦,首先要注册kvo,并在界面销毁时候要释放kvo。而RAC的出现解决了这个麻烦,从而使得mvvm的写法变得更方便了。也就是说mvvm要用到kvo思想来监听数据源的变化,从而让视图变化。rac代替了kvo的这种繁琐写法。mvvm用的是kvo思想,rac不是必须的,但是用了更方便而已。关于rac的用发可以参考这里

MVVM

M:Model,它是模型类,就是有很多属性,每个属性名字和后台返回的字段名相同。

V:View,它是视图类,如继承与UIView类的所有类都可以认为是V层,并且Controller也属于V层,即继承与UIView,UIViewController类的所有类都属于V层。这个类里存放的都是和视图相关的逻辑代码。并且controller类里存放的是一些胶水代码(就是起到粘合作用的代码)。和p层有区别,加入了视图和数据源的绑定机制。

VM:viewModel,它是vm层,这里是主要写网络请求,数据逻辑的地方。处理和视图无关的数据逻辑等。这个类不该持有v层,也就是不该#import <UIKit/UIKit.h>。并且该类和p层是有区别的,它不是通过回调的方式返回到v层。而是通过kvo的方式。

三者关系是,v层持有vm层,vm层持有m层,并通过kvo的方式通知v层。

通过以上分析,其实mvvm设计模式和mvp很像。只不过是把p层中的网络请求的回调去掉了,通过kvo的方式返回到v层。并把视图和vm层进行绑定,将p层进行这两个修改后重新起一个名字叫做vm层,也就变成了mvvm了。

下边我们用一些伪代码来进一步探索MVVM的应用,其实和MVP一样,我们也需要封装出一套MVVM的基类。用这些基类可以使得我们编码更方便。

从MVP到MVVM
//ArticleListModel.h文件
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface ArticleListModel : NSObject

/** 文章内容 */
@property (copy, nonatomic) NSString *content;
/** 点赞否 */
@property (assign, nonatomic) NSInteger praise;
@end

NS_ASSUME_NONNULL_END

//ArticleListModel.m文件
#import "ArticleListModel.h"

@implementation ArticleListModel

@end

//ArticleListVC.h文件
#import "BSMvpUtilsBaseViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface ArticleListVC : BSMvpUtilsBaseViewController

@end

NS_ASSUME_NONNULL_END

//ArticleListVC.m文件
#import "ArticleListVC.h"
#import "ArticleListVM.h"

@interface ArticleListVC ()
@property (strong, nonatomic) ArticleListVM *vm;
@property (strong, nonatomic) UITableView *tableView;
@end

@implementation ArticleListVC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //v层持有vm层
    self.vm = [[ArticleListVM alloc] init];
    //初始化视图
    [self setUpUI];
    //视图与数据源绑定
    [self bindView];
    //网络请求
    [self.vm fetchData];
}
- (void)setUpUI{
    //tableView的布局等视图初始化代码
}

- (void)bindView{
    @weakify(self);
    [[RACObserve(self.vm, error) skip:1] subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        if (self.vm.error) {
            //如果有错,弹出错误Toast等
        }
    }];
    
    [[RACObserve(self.vm, arrList) skip:1] subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        if (self.vm.arrList.count == 0) {
            //显示无数据占位图等
        }else{
            //隐藏无数据占位图等
        }
        //tableView刷新数据源
        [self.tableView reloadData];
    }];
}

//列表中的某一个点赞的心形被点击
- (void)cellPraiseBtnClick:(NSIndexPath *)indexPath{
    //根据indexPath找到对应的数据源,然后根据数据源的状态请求相应的接口,最后改变数据源的状态。
    [self.vm praiseMethod:indexPath.row];
}
@end

//ArticleListVM.h文件
#import "BSMvvmUtilsBaseVM.h"
@class ArticleListModel;
NS_ASSUME_NONNULL_BEGIN

@interface ArticleListVM : BSMvvmUtilsBaseVM
/** 出错 */
@property (strong, nonatomic) NSError *error;
/** 点赞列表数据源 */
@property (copy, nonatomic) NSArray<ArticleListModel *> *arrList;
- (void)fetchData;


/**
 点赞和取消点赞方法

 @param index index
 */
- (void)praiseMethod:(NSInteger)index;

/**
 点赞,取消点赞请求

 @param isPraise 1:点在 0:取消点赞
 */
- (void)fetchPraise:(NSNumber *)isPraise;
@end

NS_ASSUME_NONNULL_END



//ArticleListVM.m文件
#import "ArticleListVM.h"
#import "ArticleListModel.h"
#import <BSUtilsBaseRequestManager.h>

@implementation ArticleListVM

- (instancetype)init{
    self = [super init];
    if (self) {
        _error = nil;
        _arrList = nil;
    }
    
    return self;
}

//网络请求
- (void)fetchData{
    [[BSUtilsBaseRequestManager new] postWithUrl:@"xxx" parmas:@{} finishBlk:^(NSDictionary * _Nonnull responseObject, NSError * _Nonnull error) {
        if (error) {
            self.error = error;
        }else{
            //数据转模型,并把转换的结果数据赋值给arrList
            self.arrList = @[];
        }
    }];
}

//点赞和取消点赞方法
- (void)praiseMethod:(NSInteger)index{
    NSMutableArray *arrTemp = [NSMutableArray arrayWithArray:self.arrList];
    ArticleListModel *model = self.arrList[index];
    NSInteger isPraise = model.praise;
    if (isPraise) {
        //当前是已经点过攒了
        //下边要请求取消点赞接口,并判断是否请求成功
        if(!self.error){
            //取消点赞成功
            model.praise = 0;
            [arrTemp replaceObjectAtIndex:index withObject:model];
            self.arrList = arrTemp;
        }
    }else{
        //当前是还没有点过攒
        //下边要请求点赞接口,并判断是否请求成功
        if(!self.error){
            //点赞成功
            model.praise = 1;
            [arrTemp replaceObjectAtIndex:index withObject:model];
            self.arrList = arrTemp;
        }
    }
   
}

//点赞,取消点赞请求
- (void)fetchPraise:(NSNumber *)isPraise{
    if(isPraise){
        [[BSUtilsBaseRequestManager new] postWithUrl:@"xxx" parmas:@{@"praise":isPraise} finishBlk:^(NSDictionary * _Nonnull responseObject, NSError * _Nonnull error) {
            self.error = error;
        }];
    }
}
@end
复制代码

总结

通过以上分析我们知道了mvvm是要把vm层和v层进行绑定的,然后我们只要改变vm层的数据源即可改变视图。这是关键。首先进行数据源和视图的绑定再改变数据源。

其实所谓的vm层和v层绑定其实就是监听vm层的数据源变化从而改变视图罢了。这种绑定利用RAC会更加方便。当然了不用RAC也可以的只是麻烦些而已。

总是要记住首先vm层和视图层的绑定,之后只要操作vm层的数据源即可。比如上述的代码我要显示列表界面,首先监听vm层的arrList,只要有变化就进入回调,在回调中判断是否要显示空界面还是具体的列表界面。这就是所谓的绑定。之后我们网络请求,如果请求成功就对arrList赋值,这个过程就是在改变vm层的数据源,从而使得视图更新。

在比如我们要对列表中的某个心形进行点击(这时候心形有两种状态的),进行点赞或者取消点赞。这时候我们根据index找到对应的数据源,进行网络请求,在把对应的数据源praise状态改变重新赋值给vm层的arrList属性即可,因为之前arrList数据源在和视图绑定着呢。所以这时候改变arrList从而更新了视图。

当你用了mvvm这种编码方式时候,可以感觉到减少了刷新代码,不必每次改变完数据后都要手动去写刷新视图的代码了。原因是绑定只要绑定一次即可,就在不停的监听数据的变化了。其实不仅仅是减少了刷新视图的代码,同时编码方式变了,思想变了。变成了数据驱动视图了。至于mvp好还是mvvm好,我个人觉得mvvm这种思想还是挺有趣的,同时这种数据驱动视图确实是普遍现象。而且这是一种新的有趣的编码方式。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Design for ROI

Web Design for ROI

Lance Loveday、Sandra Niehaus / New Riders Press / 2007-10-27 / USD 39.99

Your web site is a business--design it like one. Billions of dollars in spending decisions are influenced by web sites. So why aren't businesses laser-focused on designing their sites to maximize thei......一起来看看 《Web Design for ROI》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

MD5 加密
MD5 加密

MD5 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具