iOS中的MVP模式初探
以前在項目中都寫的是MVC模式, 由于現在在項目中要學習MVP模式, 所以找了一個Demo研究了一下. 就簡單說說自己的看法吧.
先說一下MVC模式, 示意圖如下:
MVC模式示意圖
-
模型拿到數據, 可能是數據庫或者網絡數據
最簡單的比方, 我們拿到一個模型數組了之后, 這個就相當于是一個數據源.
-
將數據傳遞給控制器, 控制器經過簡單地加工
數據源經過簡單地處理加工, 比如在tableView中, 我們可能會使用數據源方法, 將模型數組中的元素取出來, 傳遞給View層, 比如cell
-
將加工后的數據展示出來
cell展示模型中的數據
那么MVP模式又是怎樣的呢?請看下圖
MVP模式示意圖
從上圖可以看出, 從MVC中又抽象出了P層, 即Presenter層
-
Controller其實將view和viewController傳遞給了P層, 這樣P層其實就擁有了控制器的權利, 完全可以行使控制器的職責.
-
Controller又持有Presenter, 那么它只需要調用P層暴露出的接口, 就完全可以完成整個業務邏輯和頁面展示
關于C端和P端的循環引用的問題, 直接用weak關鍵字就可以解決了
利用代碼來說明一下問題:
-
這是一個Presenter的Protocol, 所有的P層的類都要遵循這個Protocol
#import /**
作為P : presenter 是管理 view viewController model這個三個中間人,負責UI刷新
視圖的交互總是和VC 關聯著的
*/
@protocol TGPresenterProtocol @optional
// 處理View視圖相關操作 -- 協議的遵守者
- (void)setView:(NSObject *)view;
// 處理事件的相關響應
- (void)setViewController:(UIViewController *)viewController;
// 展示
- (void)present;
// 加載model
- (void)presentWithModel:(id)model viewController:(UIViewController *)viewController;
@end
-
可以看出, P層是可以拿到view或者viewController的, 并且可以在實現set方法的時候做一些事情. 這個稍后再講
-
另外, P層還可以展示數據, 直接展示數據, present方法, 利用模型展示數據, 利用presentWithModel:方法
-
比如, 在一個遵循了TGPresenterProtocol的Presenter類中
把需要管理的view傳遞給P,
- (instancetype)initWithTableView:(UITableView *)view{
self = [super init];
if (!self) {
return nil;
}
_view = view;
_view.delegate = self;
_view.dataSource = self;
_view.separatorStyle = UITableViewCellSeparatorStyleNone;
// 自適應高度
_view.rowHeight = UITableViewAutomaticDimension;
_view.estimatedRowHeight = 100;
return self;
}
- (void)setView:(UITableView *)view{
// 設置視圖
_view = view;
_view.delegate = self;
_view.dataSource = self;
_view.separatorStyle = UITableViewCellSeparatorStyleNone;
// 自適應高度
_view.rowHeight = UITableViewAutomaticDimension;
_view.estimatedRowHeight = 100;
}
-
比如上面的代碼, 將tableView的數據源和代理都給了P, 那么P就相當于行使了控制器的權力, 當P層拿到數據時(沒錯, P層是持有Model的):
- (void)loadHPData{
NSString *dataPath = [[NSBundle mainBundle] pathForResource:@"testCellData" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:dataPath];
NSError *error;
NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(@"error = %@",error.localizedDescription);
}
NSLog(@"dataDic = %@",dataDic);
// model 要處理好數據的顯示格式
self.hpModel = [[CellSelfSizeModel alloc] initWithDic:dataDic];
// 刷新
[self present];
}
-
走Present方法, 實際就是tableView的reloadData:
- (void)present{
[self.view reloadData];
}
-
然后重走tableView的數據源方法. 將數據分發給cell去展示:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.hpModel.data.listArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *ID = @"";
cellType type;
CelllSelfSizeListModel *newsList;
if (indexPath.row > self.hpModel.data.listArray.count - 1) {
newsList = nil;
}else{
newsList = self.hpModel.data.listArray[indexPath.row];
}
if (newsList.orginImg.length>0) {
// 有圖片
type = NewsInListCellTypeHavePic;
}else{
// 無圖片
type = NewsInListCellTypeOnlyWord;
}
ID = [NSString stringWithFormat:@"reusId%ld",(long)type];
SelfSizeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[SelfSizeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID cellType:type];
}
cell.cellModel = newsList;
return cell;
}
這樣就實現了Controller, View, Model的解耦. 給大家看看控制器做的事情:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = @"MVP Demo";
// 布局
[self initViews];
[self setUpConstraints];
self.hpPresenter = [TGHPPresenter new];
// 視圖對象
self.hpPresenter.view = self.tableView;
// 控制器對象
self.hpPresenter.viewController = self;
// 外邊是要傳入參進去的 -- 數據模型
[self.hpPresenter loadHPData];
}
只需要初始化P層, 然后調P層的接口就可以了. 至于P層內部的邏輯, 我不需要知道
-
V層也只專注于視圖的創建
-
M層只專注于模型的構建(字典->模型)
-
這樣分層, 解耦的思想在程序設計中是極為重要的. 其實也可以看出MVP是對MVC模式的進一步抽象.
代碼Demo是我們老大寫的, 我只是分析了一波
來自:http://www.cocoachina.com/ios/20171106/21062.html