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
相關文章:
