美文网首页
MVVM简要

MVVM简要

作者: 大成小栈 | 来源:发表于2021-04-19 17:38 被阅读0次

    MVVM(M V VM,即Model、ViewController/View、ViewModel)可以看成是在MVC模式上的更进一步的封装。MVVM更注重解耦,但也增加了代码量,这样带来的好处是代码结构分层更细,模块功能更具体,方便测试。


    MVVM交互图 以TableView为例的MVVM架构实现

    根据以上两图的层次对应,其中,V包括了ViewController/View,ViewModel包括了TableViewModel/TableViewDataSource/TableViewDelegate。其实,ViewModel就是对数据处理逻辑的剥离,将数据处理逻辑从MVC中的Controller中独立出来,从而Controller中就只留一些简单的交互。例如,网络请求、从数据库中获取数据等均可以置于ViewModel中(对于UITabelView来说,得益于UITableViewDataSource、UITableViewDelegate这两个代理,使得tabelView内容的更新,也可以独立出来,做为ViewModel的一部分。这一点,非常值得借鉴)。

    在MVVM的结构中,要非常注意循环引用的发生,适时使用weak。

    以UITabelView为例,的MVVM代码:

    Model:
    //// CustomModel.h
    #import <Foundation/Foundation.h>
    
    @interface CustomModel : NSObject
    @property (nonatomic,strong) NSString *title;
    @end
    
    ////CustomModel. m
    #import "CustomModel.h"
    
    @implementation CustomModel
    @end
    
    ViewController/View:
    //// CustomTableViewCell.h
    #import <UIKit/UIKit.h>
    
    @interface CustomTableViewCell : UITableViewCell
    @property(nonatomic,strong) UILabel *titleLabel;
    @end
    
    ////CustomTableViewCell. m
    #import "CustomTableViewCell.h"
    
    @implementation CustomTableViewCell
    
    - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        if (self) {
            // Initialization code
            _titleLabel=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, WScreen, 50)];
            [self.contentView addSubview:_titleLabel];
            _titleLabel.backgroundColor=[UIColor whiteColor];
            _titleLabel.font=[UIFont systemFontOfSize:14];
           
        }
        return self;
    }
    
    @end
    
    ==================================================
    
    ////TableViewController. h
    #import <UIKit/UIKit.h>
    @interface TableViewController : UIViewController
    
    @end
    
    ////TableViewController. m
    #import "TableViewController.h"
    #import "YiRefreshHeader.h"
    #import "YiRefreshFooter.h"
    #import "TableViewModel.h"
    #import "TableViewDataSource.h"
    #import "TableViewDelegate.h"
    @interface TableViewController () {
    
        YiRefreshHeader *refreshHeader;
        YiRefreshFooter *refreshFooter;
        NSMutableArray *totalSource;
        TableViewModel *tableViewModel;
        UITableView *tableView;
        TableViewDataSource *tableViewDataSource;
        TableViewDelegate *tableViewDelegate;
    }
    
    @end
    
    @implementation TableViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        if (iOS7) {
            self.edgesForExtendedLayout = UIRectEdgeBottom | UIRectEdgeLeft | UIRectEdgeRight;
        }
        self.title=@"MVVMDemo With TableView";
        self.view.backgroundColor=[UIColor whiteColor];
        
        tableView=[[UITableView alloc] initWithFrame:CGRectMake(0, 0, WScreen, HScreen-64) style:UITableViewStylePlain];
        [self.view addSubview:tableView];
        tableViewDataSource=[[TableViewDataSource alloc] init];
        tableViewDelegate=[[TableViewDelegate alloc] init];
        tableView.dataSource=tableViewDataSource;
        tableView.delegate=tableViewDelegate;
        tableViewModel=[[TableViewModel alloc] init];
        totalSource=0;
        
    //    YiRefreshHeader  头部刷新按钮的使用
        refreshHeader=[[YiRefreshHeader alloc] init];
        refreshHeader.scrollView=tableView;
        [refreshHeader header];
        __weak typeof(self) weakSelf = self;
        refreshHeader.beginRefreshingBlock=^(){
            __strong typeof(self) strongSelf = weakSelf;
            [strongSelf headerRefreshAction];
        };
        
    //    是否在进入该界面的时候就开始进入刷新状态
        [refreshHeader beginRefreshing];
    
    //    YiRefreshFooter  底部刷新按钮的使用
        refreshFooter=[[YiRefreshFooter alloc] init];
        refreshFooter.scrollView=tableView;
        [refreshFooter footer];
        
        refreshFooter.beginRefreshingBlock=^(){
            __strong typeof(self) strongSelf = weakSelf;
            [strongSelf footerRefreshAction];
        };
        
    }
    
    - (void)headerRefreshAction {
       
        [tableViewModel headerRefreshRequestWithCallback:^(NSArray *array){
            totalSource=(NSMutableArray *)array;
            tableViewDataSource.array=totalSource;
            tableViewDelegate.array=totalSource;
            [refreshHeader endRefreshing];
            [tableView reloadData];
        }];
    
    }
    
    - (void)footerRefreshAction {
        [tableViewModel footerRefreshRequestWithCallback:^(NSArray *array){
            [totalSource addObjectsFromArray:array] ;
            tableViewDataSource.array=totalSource;
            tableViewDelegate.array=totalSource;
            [refreshFooter endRefreshing];
            [tableView reloadData];
        
        }];
      
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    
    ViewModel
    ////TableViewModel.h
    #import <Foundation/Foundation.h>
    
    typedef void (^callback) (NSArray *array);
    
    @interface TableViewModel : NSObject
    
    //tableView头部刷新的网络请求
    - (void)headerRefreshRequestWithCallback:(callback)callback;
    //tableView底部刷新的网络请求
    - (void)footerRefreshRequestWithCallback:(callback)callback;
    
    @end
    
    ////TableViewModel.m
    #import "TableViewModel.h"
    #import "CustomModel.h"
    @interface TableViewModel ()
    
    @end
    
    @implementation TableViewModel
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            
        }
        return self;
    }
    
    - (void)headerRefreshRequestWithCallback:(callback)callback {
            //  后台执行:
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                sleep(2);
                dispatch_async(dispatch_get_main_queue(), ^{
                    //               主线程刷新视图
                    NSMutableArray *arr=[NSMutableArray array];
                    for (int i=0; i<16; i++) {
                        int x = arc4random() % 100;
                        NSString *string=[NSString stringWithFormat:@"    (random%d) 君子性非异也,善假于物也!",x];
                        CustomModel *model=[[CustomModel alloc] init];
                        model.title=string;
                        [arr addObject:model];
                    }
                    callback(arr);
                });
            });
    }
    
    - (void )footerRefreshRequestWithCallback:(callback)callback {
            //  后台执行:
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                sleep(2);
                dispatch_async(dispatch_get_main_queue(), ^{
                    //               主线程刷新视图
                    NSMutableArray *arr=[NSMutableArray array];
                    for (int i=0; i<16; i++) {
                        int x = arc4random() % 100;
                        NSString *string=[NSString stringWithFormat:@"    (random%d) 君子性非异也,善假于物也!",x];
                        CustomModel *model=[[CustomModel alloc] init];
                        model.title=string;
                        [arr addObject:model];
                    }
                    callback(arr);
                });
            });
    }
    
    @end
    
    ==================================================
    
    //// TableViewDataSource.h
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    @interface TableViewDataSource : NSObject<UITableViewDataSource>
    
    @property (nonatomic,strong) NSArray *array;
    
    @end
    
    //// TableViewDataSource.m
    #import "TableViewDataSource.h"
    #import "CustomTableViewCell.h"
    
    @implementation TableViewDataSource
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return _array.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
        if (cell == nil) {
            cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
        }
        cell.titleLabel.text=((CustomModel *)[_array objectAtIndex:indexPath.row]).title;
        return cell;
    }
    
    @end
    
    ==================================================
    
    //// TableViewDelegate.h
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    @interface TableViewDelegate : NSObject<UITableViewDelegate>
    @property (nonatomic,strong) NSArray *array;
    @end
    
    //// TableViewDelegate.m
    #import "TableViewDelegate.h"
    
    @implementation TableViewDelegate
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        if (_array.count>0) {
            UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"" message:((CustomModel *)[_array objectAtIndex:indexPath.row]).title delegate:nil cancelButtonTitle:@"sure" otherButtonTitles:nil, nil];
            [alert show];
        }    
    }
    @end
    

    ReactiveCocoaRxSwift 等框架对MVVM有非常好的延伸和实现,学无止境!

    参考文章:
    https://github.com/coderyi/MVVMDemo
    https://github.com/LXManMan/LXMVVMExample
    https://teehanlax.com/blog/model-view-viewmodel-for-ios/

    相关文章

      网友评论

          本文标题:MVVM简要

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