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

 

 本文由用戶 a282149042 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!