Get into the habit of writing together! This is the 9th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .
MVP
Protocol Oriented Programming, ie Model View Presenter
(Model View Coordinator).
feature
- Amortization of tasks: Divide the most important tasks into
Presenter
andModel
withView
less functions - Testability: Due to a functionally simple
View
layer, testing business logic becomes simple - Ease of use: More code than using
MVC
patterns, butMVP
patterns have a very clear structure
So, MVC
the MVP
difference with and is that there is no direct communication between MVP
neutral Model
and .View
Design Patterns
Model
The layer is not just to create a data object, it should also contain network requests, and dataCache
manipulationView
Layers are some encapsulation, reusePresenter
The layer does not involve network requests and operations of data , but is just a bridge toCache
build aModel
layer and a layerView
Advantage
- The model is completely separated from the view, modify the view without affecting the model
- Models can be used more efficiently because all interactions are
Presenter
in - Put logic in
Presenter
, you can unit test away from the user interface - You can use one
Presener
for multiple views without changingPresenter
the logic. This feature is very useful because the view always changes more frequently than the model
UI
with Model
decoupling
Create LGProtocol
and implement Cell
the event interface of the button click in the middle
#import <Foundation/Foundation.h>
@protocol LGProtocol <NSObject>
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath;
@end
复制代码
In , the method Present
that implements LGProtocol
the protocoldidClickNum
#import <Foundation/Foundation.h>
#import "Model.h"
#import "LGProtocol.h"
#import <YYKit.h>
@interface Present : NSObject<LGProtocol>
@property (nonatomic, strong) NSMutableArray *dataArray;
@property (nonatomic, weak) id<LGProtocol> delegate;
@end
@implementation Present
- (instancetype)init{
if (self = [super init]) {
[self loadData];
}
return self;
}
- (void)loadData{
NSArray *temArray =
@[
@{@"name":@"HK",@"imageUrl":@"http://HK",@"num":@"99"},
@{@"name":@"KD",@"imageUrl":@"http://KD",@"num":@"99"},
@{@"name":@"CC",@"imageUrl":@"http://CC",@"num":@"99"},
@{@"name":@"KC",@"imageUrl":@"http://KC",@"num":@"59"},
@{@"name":@"LA",@"imageUrl":@"http://LA",@"num":@"24"}];
for (int i = 0; i<temArray.count; i++) {
Model *m = [Model modelWithDictionary:temArray[i]];
[self.dataArray addObject:m];
}
}
#pragma mark -LGProtocol
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath{
@synchronized (self) {
if (indexpath.row < self.dataArray.count) {
Model *model = self.dataArray[indexpath.row];
model.num = num;
}
}
}
#pragma mark - lazy
- (NSMutableArray *)dataArray{
if (!_dataArray) {
_dataArray = [NSMutableArray arrayWithCapacity:10];
}
return _dataArray;
}
@end
复制代码
In MVCTableViewCell
, remove UI
the Model
data binding for the pair. In the interactive method of the button click, the delegate
method didClickNum
called
- (void)didClickAddBtn:(UIButton *)sender{
self.num++;
}
- (void)setNum:(int)num{
_num = num;
self.numLabel.text = [NSString stringWithFormat:@"%d",self.num];
// 发出响应 model delegate UI
if (self.delegate && [self.delegate respondsToSelector:@selector(didClickNum:indexpath:)]) {
[self.delegate didClickNum:self.numLabel.text indexpath:self.indexPath];
}
}
// 删除UI对Model的数据绑定
//- (void)setModel:(Model *)model{
// _model = model;
// self.numLabel.text = model.num;
// self.nameLabel.text = model.name;
//}
复制代码
Come to the VC
code , complete the data binding of the middle pair, LMDataSource
and the setting of theBlock
Cell
UI
Model
delegate
indexPath
#import "MVCViewController.h"
#import "LMDataSource.h"
#import "MVCTableViewCell.h"
#import "Present.h"
#import "Model.h"
#import "LGView.h"
@interface MVCViewController ()
@property (nonatomic, strong) LGView *lgView;
@property (nonatomic, strong) LMDataSource *dataSource;
@property (nonatomic, strong) Present *pt;
@end
@implementation MVCViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 建立关系
self.view = self.lgView;
[self.dataSource setDataArray:self.pt.dataArray];
[self.lgView setDataSource:self.dataSource];
}
#pragma mark - lazy
// UI布局代码
- (LGView *)lgView{
if(!_lgView){
_lgView = [[LGView alloc] initWithFrame:self.view.bounds];
}
return _lgView;
}
// 数据提供层
- (Present *)pt{
if(!_pt){
_pt = [[Present alloc] init];
}
return _pt;
}
// 数据代理层
- (LMDataSource *)dataSource{
if(!_dataSource){
__weak typeof(self) weakSelf = self;
_dataSource = [[LMDataSource alloc] initWithIdentifier:[MVCTableViewCell reuserId] configureBlock:^(MVCTableViewCell *cell, Model *model, NSIndexPath *indexPath) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
cell.numLabel.text = model.num;
cell.nameLabel.text = model.name;
cell.delegate = strongSelf.pt;
cell.indexPath = indexPath;
}];
}
return _dataSource;
}
@end
复制代码
two-way binding
When the following requirements are encountered during development, two-way binding between UI and Model is required. Cell
For example: the triggered didClickAddBtn
event, when num++
greater than 5
, the UI
layer only displays the first two data
Modify LGProtocol
, add UI
refresh event interface
#import <Foundation/Foundation.h>
@protocol LGProtocol <NSObject>
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath;
- (void)reloadUI;
@end
复制代码
Present
The method in the modification didClickNum
, increase num
greater than 5
, keep only the first two data, and call delegate
the reloadUI
method to refreshUI
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath{
@synchronized (self) {
if (indexpath.row < self.dataArray.count) {
Model *model = self.dataArray[indexpath.row];
model.num = num;
if ([num intValue] > 5) {
[self.dataArray removeAllObjects];
NSArray *temArray =
@[
@{@"name":@"HK",@"imageUrl":@"http://HK",@"num":@"99"},
@{@"name":@"KC",@"imageUrl":@"http://KC",@"num":@"99"}];
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(reloadUI)]) {
[self.delegate reloadUI];
}
}
}
}
}
复制代码
Modify LGView
, implement LGProtocol
the refresh UI
method of the protocol
#import <UIKit/UIKit.h>
#import "MVCTableViewCell.h"
#import "LGProtocol.h"
@interface LGView : UIView<LGProtocol>
@property (nonatomic, strong) UITableView *tableView;
- (void)setDataSource:(id<UITableViewDataSource>)dataSource;
@end
@implementation LGView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.tableView];
}
return self;
}
- (void)setDataSource:(id<UITableViewDataSource>)dataSource{
self.tableView.dataSource = dataSource;
}
- (void)reloadUI{
[self.tableView reloadData];
}
- (UITableView *)tableView{
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:self.frame style:UITableViewStylePlain];
_tableView.tableFooterView = [UIView new];
_tableView.backgroundColor = [UIColor whiteColor];
[_tableView registerClass:[MVCTableViewCell class] forCellReuseIdentifier:[MVCTableViewCell reuserId]];
}
return _tableView;
}
@end
复制代码
Modify MVCViewController
, will UI
and Model
build relationship
- (void)viewDidLoad {
[super viewDidLoad];
// 建立关系
self.view = self.lgView;
[self.dataSource setDataArray:self.pt.dataArray];
[self.lgView setDataSource:self.dataSource];
//将UI和Model建立关系
self.pt.delegate = self.lgView;
}
复制代码
For the above MVP
simple case, there are still many flaws. This kind of rudimentary code is difficult to meet even the common needs in development
For example the following situations:
- encounter more complex
Cell
forms - Using too much iso-
delegate
glue code - When the module level is deeper, it is difficult to communicate with each other
Therefore, in response to the above problems, but also to introduce MVP
the real way of use.