iOS的 MVP模式 學(xué)習(xí)

這兩天時(shí)間寬松一點(diǎn),所以我也來(lái)學(xué)學(xué)MVP的設(shè)計(jì)模式,有人說(shuō)是架構(gòu),管他呢,好用就行。so,開(kāi)干! 后邊有OC版本的demo

  1. 打開(kāi)了Google,搜了一下關(guān)鍵字 MVP iOS,然后發(fā)現(xiàn)了一些文章,最后是這篇文章帶給我對(duì)MVP 的一些認(rèn)識(shí)。
  2. MVP似乎有好多的變種,作者所說(shuō)的這種有如下特點(diǎn):
    (原文如下:)
    • the view part of the MVP consists of both UIViews and UIViewController
    • the view delegates user interactions to the presenter
    • the presenter contains the logic to handle user interactions
    • the presenter communicates with model layer, converts the data to UI friendly format, and updates the view
    • the presenter has no dependencies to UIKit
    • the view is passive (dump)
      稍微翻譯一下
    • MVP的 V 層是由UIViewController 和UIView 共同組成
    • view 將委托presenter 對(duì)它自己的操作,(簡(jiǎn)單來(lái)說(shuō)就是presenter發(fā)命令來(lái)控制view的交互,要你隱藏就隱藏,叫你show 你就乖乖的show)
    • presenter擁有對(duì) view交互的邏輯(就是上面說(shuō)的意思)
    • presenter跟model層通信,并將數(shù)據(jù)轉(zhuǎn)化成對(duì)適應(yīng)UI的數(shù)據(jù)并更新view
    • presenter不需要依賴(lài)UIKit
    • view層是單一,因?yàn)樗潜粍?dòng)接受命令,沒(méi)有主動(dòng)能力

如下


The MVP pattern

presenter 作為業(yè)務(wù)邏輯的處理者,首先要向model層拿數(shù)據(jù),所以它將可以向model層通信。其次,UI的處理權(quán)移交給了它,所以它需要與view成通訊,發(fā)送命令改變UI。同時(shí),UI的響應(yīng)將觸發(fā)業(yè)務(wù)邏輯的處理,所以view 層向presenter層通訊,告訴他用戶(hù)做了什么操作,需要你反饋對(duì)應(yīng)的數(shù)據(jù)來(lái)更新UI。這樣就完成了從用戶(hù)交互獲得交互反饋到整個(gè)業(yè)務(wù)邏輯。

  1. 說(shuō)啥都是廢話(huà),交出代碼,我們還能做朋友
    首先看下結(jié)構(gòu)
三個(gè)主要類(lèi)和一個(gè)協(xié)議

UserViewProtocol 協(xié)議定義了一下方法,這些方法其實(shí)就是presenter對(duì)view層發(fā)送的命令
#import <Foundation/Foundation.h>
@protocol UserViewProtocol <NSObject>
-(void) userViewDataSource:(NSArray*)data;
-(void) showIndicator;
-(void) hideIndicator;
-(void) showEmptyView;
@end

UserService 類(lèi)是用來(lái)請(qǐng)求數(shù)據(jù)給presenter的,也能算是model層吧。我就只定義了一個(gè)方法。

-(void)getUserInfosSuccess:(SuccessHandler )success andFail:(FailHandler) failure

這一層,其實(shí)也可以很復(fù)雜,這就涉及網(wǎng)絡(luò)層的架構(gòu)了,可以去看看casatwy大神關(guān)于網(wǎng)絡(luò)層架構(gòu)的思路,我也正在學(xué)習(xí) 。

ViewController類(lèi)則是UI層,它實(shí)現(xiàn)了tableview自己的協(xié)議,還實(shí)現(xiàn)了用戶(hù)交互的協(xié)議 UserViewProtocol,也就說(shuō),presenter向UI層發(fā)送命令,其實(shí)是發(fā)給UI層的viewController,實(shí)際上是控制器來(lái)被動(dòng)的更新UI。這個(gè)不管是MVC還是MVP,view的實(shí)際控制權(quán)應(yīng)該都是viewController,這個(gè)理解應(yīng)該沒(méi)錯(cuò)吧。
協(xié)議中的幾個(gè)方法實(shí)現(xiàn)如下。

-(void)userViewDataSource:(NSArray*)data{
 self.friendlyUIData = data;
 [self.tableview reloadData];
}
-(void) showIndicator{
 self.indicator.hidden = NO;
}
-(void) hideIndicator{
 self.indicator.hidden = YES;
}
-(void) showEmptyView{
 UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"Alert" message:@"show empty view" preferredStyle:UIAlertControllerStyleAlert];
 [alertView addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil]];
 [self presentViewController:alertView animated:YES completion:^{
 }];
}

另外,在viewDidload中,調(diào)用了presenter的兩個(gè)public 方法

 self.presenter = [Presenter new];
 [self.presenter attachView:self];
 [self.presenter fetchData];

那就來(lái)看看Presenter類(lèi),這個(gè)類(lèi)我在demo中加了不少的注釋?zhuān)饕菫榱死砬遄约旱乃悸?br> 先說(shuō)attachView 方法,這個(gè)方法是對(duì)外公開(kāi)的,目的就是為了將實(shí)現(xiàn)了UserViewProtocol 協(xié)議的對(duì)象(其實(shí)應(yīng)該就是控制器,因?yàn)関iew的直接操作者就是view Controller)綁定到presenter 上,說(shuō)白了就是presenter 可以直接拿到實(shí)現(xiàn)了UserViewProtocol 協(xié)議的對(duì)象,并且向他發(fā)送命令(協(xié)議實(shí)現(xiàn)的方法,前面有說(shuō)到),具體該方法的實(shí)現(xiàn)

@interface Presenter()
@property (nonatomic,strong) UserService *userService;
@property (nonatomic,weak) id<UserViewProtocol> attachView;
@end
-(void)attachView:(id <UserViewProtocol>)view{
 self.attachView = view;
 self.userService  = [UserService new];
}

注意這里用了weak 來(lái)修飾attachView 樹(shù)形,因?yàn)閜resenter和 viewController相互持有,所以必須要通過(guò)weak 來(lái)打破循環(huán)引用,這跟我們平時(shí)使用委托協(xié)議( delegate)是一樣的,只是名字換成了attachView 而已。

再來(lái)說(shuō)fetchData方法,公開(kāi)這個(gè)方法,只是為了數(shù)據(jù)請(qǐng)求有個(gè)統(tǒng)一的接口,而不需要presenter分開(kāi)多次調(diào)用,presenter自己處理所有事情,不讓viewController參和進(jìn)來(lái)。具體實(shí)現(xiàn)就看demo

最后說(shuō)一下

-(NSArray *)processOriginDataToUIFriendlyData:(NSArray *) originData{
 NSMutableArray *friendlyUIData = [NSMutableArray new];
 for (NSDictionary *dic in originData) {
  if ([[dic valueForKey:@"gender"] isEqualToString:@"males"]) {
   [friendlyUIData addObject:dic];
  }
 }
 return friendlyUIData;
}

這個(gè)私有方法是將原始數(shù)據(jù)轉(zhuǎn)換成UI所需要的數(shù)據(jù),這樣UI拿到數(shù)據(jù)就可以直接使用,而不用做各種判斷,邏輯依然放在了presenter中。而且,這個(gè)數(shù)據(jù)處理可以做成協(xié)議,輸出不同UI需要的數(shù)據(jù),這個(gè)也可以看casatwy大神 關(guān)于view架構(gòu)的文章。

這就是我的一些簡(jiǎn)單理解!有錯(cuò)誤歡迎糾正。最后,還有demo沒(méi)上啊,就想跑
demo在這里https://github.com/HecvStyle/MVPDemo

--------end--------

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容