开源库

MVC解重解耦到MVP

2019-04-05  本文已影响0人  架构师的一小步

MVP面向协议编程->

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

//第一步:问自己目的:这里是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;
        }
    }
    }
  
第一步:明确目的是让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.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

//
//  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

上一篇 下一篇

猜你喜欢

热点阅读