一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して9日目です。クリックしてイベントの詳細をご覧ください。
MVP
プロトコル指向プログラミング、すなわちModel View Presenter
(モデルビューコーディネーター)。
特徴
- タスクの償却:最も重要なタスク
Presenter
をより少ない機能に分割Model
しますView
- テスト容易性:機能的に単純な
View
レイヤーにより、ビジネスロジックのテストが簡単になります MVC
使いやすさ:パターンを使用するよりも多くのコードがありますが、MVP
パターンは非常に明確な構造を持っています
したがって、MVC
とのMVP
違いは、MVP
ニュートラルModel
との間にはView
直接の通信がないことです。
デザインパターン
Model
Cache
このレイヤーは、データオブジェクトを作成するだけでなく、ネットワークリクエストとデータ操作も含める必要がありますView
レイヤーはいくつかのカプセル化、再利用ですPresenter
レイヤーには、ネットワークリクエストやデータの操作は含まれませんが、レイヤーとレイヤーをCache
構築するための単なるブリッジです。Model
View
アドバンテージ
- モデルはビューから完全に分離されています。モデルに影響を与えずにビューを変更してください
- すべての相互作用が含ま
Presenter
れているため、モデルをより効率的に使用できます - ロジックを入れると
Presenter
、ユーザーインターフェイスから離れた場所で単体テストを行うことができます - ロジックを変更せずに、 1つ
Presener
を複数のビューに使用できます。Presenter
ビューは常にモデルよりも頻繁に変更されるため、この機能は非常に便利です。
UI
Model
デカップリングあり
中央のボタンクリックのイベントインターフェイスを作成LGProtocol
して実装しますCell
#import <Foundation/Foundation.h>
@protocol LGProtocol <NSObject>
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath;
@end
复制代码
で、プロトコルPresent
を実装するメソッドLGProtocol
didClickNum
#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
复制代码
で、ペアのデータバインディングをMVCTableViewCell
削除します。ボタンクリックのインタラクティブな方法では、UI
Model
delegate
didClickNum
- (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;
//}
复制代码
VC
コードに来て、真ん中のペアのデータバインディングを完了LMDataSource
し、Block
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
复制代码
双方向バインディング
開発中に次の要件が発生した場合、UIとモデル間の双方向バインディングが必要です。例:トリガーされCell
たdidClickAddBtn
イベント、num++
より大きい場合5
、UI
レイヤーは最初の2つのデータのみを表示します
変更、更新イベントインターフェイスLGProtocol
の追加UI
#import <Foundation/Foundation.h>
@protocol LGProtocol <NSObject>
- (void)didClickNum:(NSString *)num indexpath:(NSIndexPath *)indexpath;
- (void)reloadUI;
@end
复制代码
変更Present
のメソッドは、より大きくdidClickNum
増加し、最初の2つのデータのみを保持し、メソッドを呼び出して更新しますnum
5
delegate
reloadUI
UI
- (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];
}
}
}
}
}
复制代码
プロトコルの更新メソッドを変更LGView
、実装しますLGProtocol
UI
#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
复制代码
変更MVCViewController
、意志UI
、Model
関係の構築
- (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;
}
复制代码
上記のMVP
単純なケースでは、まだ多くの欠陥があります。この種の基本的なコードは、開発における一般的なニーズでさえ満たすのが困難です。
たとえば、次の状況です。
- より複雑な
Cell
フォームに遭遇する - あまりにも多くのアイソ
delegate
グルーコードを使用している - モジュールレベルが深くなると、相互の通信が困難になります。
したがって、上記の問題に対応するだけでなくMVP
、実際の使用方法を紹介します。