美文网首页开源库
MVC解重解耦到MVP

MVC解重解耦到MVP

作者: 架构师的一小步 | 来源:发表于2019-04-05 13:11 被阅读0次

    MVP面向协议编程->

    • 主要目的:解重管理器Controller层,解耦view和model之间相互依赖的关系
    • 解决方案:添加中介者层,降低view和model之间的耦合性。运用了中介者模式
    • 代码部分:通过在中介者层,通过协议代理进行实现view和model之间的事件处理

    example:UI改变更新model,model改变更新UI

    • UI改变更新model
    //第一步:问自己目的:这里是UI需要更新model,让中介者去更新model
    //所以:需要将中介者对象给予UI
    __weak typeof(self) weakSelf = self;
    //左边UI,右边中介者
    cell.delegate       = weakSelf.pt;
    
    //第二步:UI层需要做的事
    1.一个遵循协议的delegate
    @property (nonatomic, weak) id<PresentDelegate> delegate;
    2.一个消息发送(UI发生改变时候需要通知那个需要改变者)
    - (void)setNum:(int)num{
        _num = num;
        self.numLabel.text = [NSString stringWithFormat:@"%d",self.num];
        //这里是通知这个代理对象进行调用
        if (self.delegate && [self.delegate respondsToSelector:@selector(didClickAddBtnWithNum:indexPath:)]) {
            [self.delegate didClickAddBtnWithNum:self.numLabel.text indexPath:self.indexPath];
        }
    }
    
    第三步:Model层需要做的是:由于这里是中介者模式所以由中介者处理model层
    1.遵循这个协议
    #import "PresentDelegate.h"
    @interface Present : NSObject<PresentDelegate>
    @property (nonatomic, weak) id<PresentDelegate> delegate;
    2.实现改变model的方法
    #pragma mark - PresentDelegate
    - (void)didClickAddBtnWithNum:(NSString *)num indexPath:(NSIndexPath *)indexPath{
       
    //    @synchronized(self){
    //        
    //    }
        
        for (int i = 0; i<self.dataArray.count; i++) {
            // 查数据 ---> 钱
            if (i == indexPath.row) {// 商品ID 容错
                Model *m = self.dataArray[indexPath.row];
                m.num    = num;
                break;
            }
        }
        }
      
    
    • model改变更新UI
    第一步:明确目的是让UI层去更新界面:这里是中介者让ui层更新界面
    //  MVPViewController.m
    //左边中介者,右边UI(这里是MVPViewController)
    self.pt.delegate          = self;
    
    第二步:中介者层
    - (void)didClickAddBtnWithNum:(NSString *)num indexPath:(NSIndexPath *)indexPath{
       
    //    @synchronized(self){
    //        
    //    }
        
        for (int i = 0; i<self.dataArray.count; i++) {
            // 查数据 ---> 钱
            if (i == indexPath.row) {// 商品ID 容错
                Model *m = self.dataArray[indexPath.row];
                m.num    = num;
                break;
            }
        }
        
        
        if ([num intValue] > 6) {
            NSArray *temArray =
            @[
              @{@"name":@"CC",@"imageUrl":@"http://CC",@"num":@"9"},
              @{@"name":@"Gavin",@"imageUrl":@"http://Gavin",@"num":@"9"},
              @{@"name":@"Cooci",@"imageUrl":@"http://Cooci",@"num":@"9"}];
            [self.dataArray removeAllObjects];
            for (int i = 0; i<temArray.count; i++) {
                Model *m = [Model modelWithDictionary:temArray[i]];
                [self.dataArray addObject:m];
            }
            //这里通知UI层进行更新UI操作
            if (self.delegate && [self.delegate respondsToSelector:@selector(reloadDataForUI)]) {
                [self.delegate reloadDataForUI];
            }
            
        }
        
    }
    
    第三步:UI层
    //  MVPViewController.m
    #pragma mark - PresentDelegate
    - (void)reloadDataForUI{
        [self.dataSource addDataArray:self.pt.dataArray];
        [self.tableView reloadData];
    }
    

    中介者模式

    这里引用的第三方组件
    podfile:
    
    pod 'YYKit', '~> 1.0.9'
    pod 'Masonry', '~> 1.1.0'
    
    • 角色一:抽象中介者
    //
    //  PresentDelegate.h
    //  003--MVP
    //
    //  Created by 王宁 on 2019/4/5.
    //  Copyright © 2019年 Cooci. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol PresentDelegate <NSObject>
    
    // UI ---> model
    - (void)didClickAddBtnWithNum:(NSString *)num indexPath:(NSIndexPath *)indexPath;
    // 刷新UI  ---> tableView VC
    - (void)reloadDataForUI;
    
    - (void)starAnmating;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    • 角色二:具体中介者
    //
    //  Present.h
    //  003--MVP
    //
    //  Created by Cooci on 2018/4/1.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import "Model.h"
    #import <YYKit.h>
    #import "PresentDelegate.h"
    
    @interface Present : NSObject<PresentDelegate>
    
    @property (nonatomic, strong) NSMutableArray *dataArray;
    
    - (void)loadData;
    
    @property (nonatomic, weak) id<PresentDelegate> delegate;
    
    
    @end
    //
    //  Present.m
    //  003--MVP
    //
    //  Created by Cooci on 2018/4/1.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import "Present.h"
    
    @implementation Present
    
    - (instancetype)init{
        if (self = [super init]) {
            
            [self loadData];  // 请求合适?
            
        }
        return self;
    }
    
    - (void)loadData{
        
        NSArray *temArray =
        @[
          @{@"name":@"CC",@"imageUrl":@"http://CC",@"num":@"9"},
          @{@"name":@"Gavin",@"imageUrl":@"http://Gavin",@"num":@"9"},
          @{@"name":@"Cooci",@"imageUrl":@"http://Cooci",@"num":@"9"},
          @{@"name":@"Dean",@"imageUrl":@"http://Dean ",@"num":@"9"},
          @{@"name":@"CC",@"imageUrl":@"http://CC",@"num":@"9"},
          @{@"name":@"Gavin",@"imageUrl":@"http://Gavin",@"num":@"9"},
          @{@"name":@"Cooci",@"imageUrl":@"http://Cooci",@"num":@"9"},
          @{@"name":@"Dean",@"imageUrl":@"http://Dean ",@"num":@"9"}];
        for (int i = 0; i<temArray.count; i++) {
            Model *m = [Model modelWithDictionary:temArray[i]];
            [self.dataArray addObject:m];
        }
        
        
      
        
    }
    
    
    #pragma mark - PresentDelegate
    - (void)didClickAddBtnWithNum:(NSString *)num indexPath:(NSIndexPath *)indexPath{
       
    //    @synchronized(self){
    //        
    //    }
        
        for (int i = 0; i<self.dataArray.count; i++) {
            // 查数据 ---> 钱
            if (i == indexPath.row) {// 商品ID 容错
                Model *m = self.dataArray[indexPath.row];
                m.num    = num;
                break;
            }
        }
        
        
        if ([num intValue] > 6) {
            NSArray *temArray =
            @[
              @{@"name":@"CC",@"imageUrl":@"http://CC",@"num":@"9"},
              @{@"name":@"Gavin",@"imageUrl":@"http://Gavin",@"num":@"9"},
              @{@"name":@"Cooci",@"imageUrl":@"http://Cooci",@"num":@"9"}];
            [self.dataArray removeAllObjects];
            for (int i = 0; i<temArray.count; i++) {
                Model *m = [Model modelWithDictionary:temArray[i]];
                [self.dataArray addObject:m];
            }
            
            if (self.delegate && [self.delegate respondsToSelector:@selector(reloadDataForUI)]) {
                [self.delegate reloadDataForUI];
            }
            
        }
        
    }
    
    #pragma mark - lazy
    
    - (NSMutableArray *)dataArray{
        if (!_dataArray) {
            _dataArray = [NSMutableArray arrayWithCapacity:10];
        }
        return _dataArray;
    }
    
    @end
    
    
    • model层
    //
    //  Model.h
    //  MVPDemo
    //
    //  Created by Cooci on 2018/3/31.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface Model : NSObject
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSString *imageUrl;
    @property (nonatomic, copy) NSString *num;
    
    @end
    //
    //  Model.m
    //  MVPDemo
    //
    //  Created by Cooci on 2018/3/31.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import "Model.h"
    
    @implementation Model
    
    @end
    
    
    • 通用的tableviewsource层
    //
    //  LMDataSource.h
    //  LMShopCart
    //
    //  Created by Cooci on 2018/3/29.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    typedef void (^CellConfigureBefore)(id cell, id model, NSIndexPath * indexPath);
    
    
    @interface LMDataSource : NSObject<UITableViewDataSource,UICollectionViewDataSource>
    
    @property (nonatomic, strong)  NSMutableArray *dataArray;;
    
    //自定义
    - (id)initWithIdentifier:(NSString *)identifier configureBlock:(CellConfigureBefore)before;
    
    //sb
    @property (nonatomic, strong) IBInspectable NSString *cellIdentifier;
    
    @property (nonatomic, copy) CellConfigureBefore cellConfigureBefore;
    
    
    
    - (void)addDataArray:(NSArray *)datas;
    
    - (id)modelsAtIndexPath:(NSIndexPath *)indexPath;
    
    @end
    //
    //  LMDataSource.m
    //  LMShopCart
    //
    //  Created by Cooci on 2018/3/29.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import "LMDataSource.h"
    
    @implementation LMDataSource
    
    - (id)initWithIdentifier:(NSString *)identifier configureBlock:(CellConfigureBefore)before {
        if(self = [super init]) {
            _cellIdentifier = identifier;
            _cellConfigureBefore = [before copy];
        }
        return self;
    }
    
    
    - (void)addDataArray:(NSArray *)datas{
        if(!datas) return;
        
        if (self.dataArray.count>0) {
            [self.dataArray removeAllObjects];
        }
    
        [self.dataArray addObjectsFromArray:datas];
        
    }
    
    - (id)modelsAtIndexPath:(NSIndexPath *)indexPath {
        return self.dataArray.count > indexPath.row ? self.dataArray[indexPath.row] : nil;
    }
    
    
    
    #pragma mark UITableViewDataSource
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return !self.dataArray  ? 0: self.dataArray.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];
        id model = [self modelsAtIndexPath:indexPath];
        if(self.cellConfigureBefore) {
            self.cellConfigureBefore(cell, model,indexPath);
        }
        
        return cell;
    }
    
    
    #pragma mark UICollectionViewDataSource
    
    
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
    {
        return !self.dataArray  ? 0: self.dataArray.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:self.cellIdentifier forIndexPath:indexPath];
        id model = [self modelsAtIndexPath:indexPath];
        
        if(self.cellConfigureBefore) {
            self.cellConfigureBefore(cell, model,indexPath);
        }
    
        return cell;
    }
    
    
    - (NSMutableArray *)dataArray{
        
        if (!_dataArray) {
            _dataArray = [NSMutableArray arrayWithCapacity:5];
        }
        return _dataArray;
        
    }
    
    
    
    @end
    
    
    • 角色三:具体同事
    //
    //  MVPTableViewCell.h
    //  MVPDemo
    //
    //  Created by Cooci on 2018/3/31.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import "Present.h"
    #import "PresentDelegate.h"
    @interface MVPTableViewCell : UITableViewCell
    @property (nonatomic, strong) UIButton *subBtn;
    @property (nonatomic, strong) UILabel *nameLabel;
    @property (nonatomic, strong) UILabel *numLabel;
    @property (nonatomic, strong) UIButton *addBtn;
    @property (nonatomic, assign) int num;
    @property (nonatomic, strong) NSIndexPath *indexPath;
    @property (nonatomic, weak) id<PresentDelegate> delegate;
    
    @end
    //
    //  MVPTableViewCell.m
    //  MVPDemo
    //
    //  Created by Cooci on 2018/3/31.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import "MVPTableViewCell.h"
    #import <Masonry.h>
    
    @implementation MVPTableViewCell
    
    
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
        
        if (self == [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
            
            [self setupUI];
        }
        
        return self;
    }
    
    - (void)layoutSubviews{
        
        [super layoutSubviews];
        
        [self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerY.equalTo(self.contentView);
            make.left.mas_equalTo(20);
        }];
        
        [self.addBtn mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerY.equalTo(self.contentView);
            make.right.mas_equalTo(-50);
            make.size.mas_equalTo(CGSizeMake(30, 30));
        }];
        
        [self.numLabel mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerY.equalTo(self.contentView);
            make.right.equalTo(self.addBtn.mas_left);
            make.size.mas_equalTo(CGSizeMake(50, 30));
        }];
        
        [self.subBtn mas_makeConstraints:^(MASConstraintMaker *make) {
            make.right.equalTo(self.numLabel.mas_left);
            make.size.centerY.equalTo(self.addBtn);
        }];
        
    }
    
    - (void)setupUI{
        [self.contentView addSubview:self.nameLabel];
        [self.contentView addSubview:self.subBtn];
        [self.contentView addSubview:self.numLabel];
        [self.contentView addSubview:self.addBtn];
        self.num = 0;
    }
    
    
    #pragma mark - Action
    
    - (void)didClickSubBtn:(UIButton *)sender{
            if ([self.numLabel.text intValue]<=0) {return;}
        self.num--;
    }
    
    - (void)didClickAddBtn:(UIButton *)sender{
        if ([self.numLabel.text intValue]>=200) {return;}
        self.num++;
    }
    
    
    #pragma mark - setter
    
    - (void)setNum:(int)num{
        _num = num;
        self.numLabel.text = [NSString stringWithFormat:@"%d",self.num];
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(didClickAddBtnWithNum:indexPath:)]) {
            [self.delegate didClickAddBtnWithNum:self.numLabel.text indexPath:self.indexPath];
        }
    }
    
    
    
    #pragma mark - LAZY
    
    - (UILabel *)numLabel{
        if (_numLabel == nil) {
            _numLabel = [[UILabel alloc] init];
            _numLabel.text = @"0";
            _numLabel.textAlignment = NSTextAlignmentCenter;
            _numLabel.font = [UIFont systemFontOfSize:20];
            _numLabel.textColor = [UIColor redColor];
        }
        return _numLabel;
    }
    
    - (UILabel *)nameLabel{
        if (_nameLabel == nil) {
            _nameLabel = [[UILabel alloc] init];
            _nameLabel.text = @"Cooci";
            _nameLabel.textAlignment = NSTextAlignmentCenter;
            _nameLabel.font = [UIFont systemFontOfSize:20];
            _nameLabel.textColor = [UIColor orangeColor];
        }
        return _nameLabel;
    }
    
    - (UIButton *)subBtn{
        if (_subBtn == nil) {
            _subBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            [_subBtn setTitle:@" - " forState:UIControlStateNormal];
            [_subBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
            _subBtn.titleLabel.font = [UIFont systemFontOfSize:20];
            [_subBtn setBackgroundColor:[UIColor blueColor]];
            [_subBtn addTarget:self action:@selector(didClickSubBtn:) forControlEvents:UIControlEventTouchUpInside];
            _subBtn.layer.cornerRadius = 15;
            _subBtn.layer.masksToBounds = YES;
            _subBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
        }
        return _subBtn;
    }
    
    - (UIButton *)addBtn{
        if (!_addBtn) {
            _addBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            [_addBtn setTitle:@" + " forState:UIControlStateNormal];
            [_addBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
            _addBtn.titleLabel.font = [UIFont systemFontOfSize:20];
            [_addBtn setBackgroundColor:[UIColor blueColor]];
            [_addBtn addTarget:self action:@selector(didClickAddBtn:) forControlEvents:UIControlEventTouchUpInside];
            _addBtn.layer.cornerRadius = 15;
            _addBtn.layer.masksToBounds = YES;
            _addBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
        }
        return _addBtn;
    }
    
    - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
        [super setSelected:selected animated:animated];
    
        // Configure the view for the selected state
    }
    
    @end
    
    //
    //  MVPViewController.h
    //  MVPDemo
    //
    //  Created by Cooci on 2018/3/31.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface MVPViewController : UIViewController
    
    @end
    
    //
    //  MVPViewController.m
    //  MVPDemo
    //
    //  Created by Cooci on 2018/3/31.
    //  Copyright © 2018年 Cooci. All rights reserved.
    //
    
    #import "MVPViewController.h"
    #import "LMDataSource.h"
    #import "MVPTableViewCell.h"
    #import "Model.h"
    #import <YYKit.h>
    #import "Present.h"
    #import "PresentDelegate.h"
    
    static NSString *const reuserId = @"reuserId";
    
    @interface MVPViewController ()<PresentDelegate>
    @property (nonatomic, strong) UITableView *tableView;
    @property (nonatomic, strong) NSMutableArray *dataArray;
    @property (nonatomic, strong) Present *pt;
    @property (nonatomic, strong) LMDataSource *dataSource;
    
    @end
    
    /**
     1:解重 : 根据 VC model view
        1.1:View ?
        1.2:cell复用 : 原因 ---> UI事件  (cellforrow) VS 数据源没有改变
            UI<---->Model  双向绑定 ? 
     2:解耦
     2.1 通讯  ---> MVP : 面向协议时编程 : 代理
     
     */
    
    @implementation MVPViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 建立连接
        self.pt = [[Present alloc] init];
        __weak typeof(self) weakSelf = self;
        self.dataSource = [[LMDataSource alloc] initWithIdentifier:reuserId configureBlock:^(MVPTableViewCell *cell, Model *model, NSIndexPath *indexPath) {
            // 函数式编程
            // RAC 编程思想之集大成者
            cell.nameLabel.text = model.name;
            cell.numLabel.text  = model.num;
            cell.indexPath      = indexPath;
            cell.delegate       = weakSelf.pt;
        }];
        [self.dataSource addDataArray:self.pt.dataArray];
        
        self.view.backgroundColor = [UIColor whiteColor];
        [self.view addSubview:self.tableView];
        self.tableView.dataSource = self.dataSource;
        self.pt.delegate          = self;
        
    }
    
    #pragma mark - PresentDelegate
    - (void)reloadDataForUI{
        [self.dataSource addDataArray:self.pt.dataArray];
        [self.tableView reloadData];
    }
    
    
    #pragma mark - lazy
    
    - (UITableView *)tableView{
        if (!_tableView) {
            _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
            _tableView.backgroundColor = [UIColor whiteColor];
            [_tableView registerClass:[MVPTableViewCell class] forCellReuseIdentifier:reuserId];
        }
        return _tableView;
    }
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    /*
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
    
    @end
    
    

    相关文章

      网友评论

        本文标题:MVC解重解耦到MVP

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