MVP:面向协议式编程 ,model<—>UI 解耦+关联
V层UI改变,通知P层,P层更新数据通知M层,M层拿到新数据通知P层,P层通知V层UI改变。
MVP 优缺点:
①模型与视图完全分离,我们可以修改视图而不影响模型;
②可以更高效的使用模型,因为所有的交互都发生在一个地方,Presenter内部;
③我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;
④如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试);
1.Present层代码
#import <Foundation/Foundation.h> #import "Model.h" @protocol PresentDelegate <NSObject> @optional //需求驱动代码 - (void)addBtnWithNum:(NSString*)num indexPath:(NSIndexPath*)indexPath; //通知 - (void)reloadUI; @end @interface Present : NSObject<PresentDelegate> @property (nonatomic, strong) NSMutableArray * dataArray ; @property (nonatomic, weak) id<PresentDelegate> delegate ; @end #import "Present.h" #import <UIKit/UIKit.h> #import "Model.h" @implementation Present - (instancetype)init { self = [super init]; if (self) { [self loadData]; } return self; } - (void)loadData { NSArray * tempArray = @[@{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}, @{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}, @{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}, @{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}]; for (int i = 0; i<tempArray.count; i++) { Model * model = [[Model alloc] init]; [model setValuesForKeysWithDictionary:tempArray[i]]; [self.dataArray addObject:model]; } } -(void)addBtnWithNum:(NSString *)num indexPath:(NSIndexPath *)indexPath { Model * model = self.dataArray[indexPath.row]; model.num = num; if ([num intValue] > 5) { NSArray * tempArray = @[@{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}, @{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}, @{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}, @{@"name":@"Hank",@"imageUrl":@"http://cc",@"num":@"99"}]; for (int i = 0; i<tempArray.count; i++) { Model * model = [[Model alloc] init]; [model setValuesForKeysWithDictionary:tempArray[i]]; [self.dataArray addObject:model]; } if (self.delegate && [self.delegate respondsToSelector:@selector(reloadUI)]) { [self.delegate reloadUI]; } } } @end
2.Cell层
#import "MVCTableViewCell.h" @implementation MVCTableViewCell - (void)awakeFromNib { [super awakeFromNib]; // Initialization code } -(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 ++; } -(void)setModel:(Model *)model { _model = model; self.numLabel.text = model.name; } - (void)setNum:(int)num { _num = num; self.numLabel.text = [NSString stringWithFormat:@"%d",self.num]; if (self.delegate && [self.delegate respondsToSelector:@selector(addBtnWithNum:indexPath:)]) { [self.delegate addBtnWithNum:self.numLabel.text indexPath:self.indexPath]; } } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } @end
使用
#import "ViewController.h" #import "HKDataSource.h" #import "MVCTableViewCell.h" #import "Present.h" #import "Model.h" static NSString * reuseId = @"reuseId"; @interface ViewController ()<PresentDelegate> @property (nonatomic, strong) UITableView * tableView; @property (nonatomic, strong) NSMutableArray * dataArray ; @property (nonatomic, strong) HKDataSource * dataSource ; @property (nonatomic, strong) Present * pt ; @end @implementation ViewController //V层UI改变,通知P层,P层更新数据通知M层,M层拿到新数据通知P层,P层通知V层UI改变。 //MVP 优缺点: //①模型与视图完全分离,我们可以修改视图而不影响模型 //②可以更高效的使用模型,因为所有的交互都发生在一个地方,Presenter内部 //③我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。 //④如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试). - (void)viewDidLoad { [super viewDidLoad]; self.pt = [[Present alloc] init]; __weak typeof(self) weakSelf = self; self.dataSource = [[HKDataSource alloc] initWithIdentifier:reuseId configureBlock:^(MVCTableViewCell *cell, Model *model, NSIndexPath *indexPath) { cell.model = model; cell.numLabel.text = model.num; cell.nameLabel.text = model.name; cell.indexPath = indexPath; cell.delegate = weakSelf.pt; }]; [self.dataSource addDataArray:self.dataArray]; self.view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:self.tableView]; self.tableView.dataSource = self.dataSource; self.pt.delegate = self; } - (void)reloadUI { [self.dataSource addDataArray:self.pt.dataArray]; [self.tableView reloadData]; } -(UITableView *)tableView { if (!_tableView) { _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; _tableView.tableFooterView = [UIView new]; _tableView.backgroundColor = [UIColor whiteColor]; [_tableView registerClass:[MVCTableViewCell class] forCellReuseIdentifier:reuseId]; } return _tableView; } @end