iOS中的MVP模式初探
以前在項(xiàng)目中都寫(xiě)的是MVC模式, 由于現(xiàn)在在項(xiàng)目中要學(xué)習(xí)MVP模式, 所以找了一個(gè)Demo研究了一下. 就簡(jiǎn)單說(shuō)說(shuō)自己的看法吧.
先說(shuō)一下MVC模式, 示意圖如下:
MVC模式示意圖
模型拿到數(shù)據(jù), 可能是數(shù)據(jù)庫(kù)或者網(wǎng)絡(luò)數(shù)據(jù)
最簡(jiǎn)單的比方, 我們拿到一個(gè)模型數(shù)組了之后, 這個(gè)就相當(dāng)于是一個(gè)數(shù)據(jù)源.
將數(shù)據(jù)傳遞給控制器, 控制器經(jīng)過(guò)簡(jiǎn)單地加工
數(shù)據(jù)源經(jīng)過(guò)簡(jiǎn)單地處理加工, 比如在tableView中, 我們可能會(huì)使用數(shù)據(jù)源方法, 將模型數(shù)組中的元素取出來(lái), 傳遞給View層, 比如cell
將加工后的數(shù)據(jù)展示出來(lái)
cell展示模型中的數(shù)據(jù)
那么MVP模式又是怎樣的呢?請(qǐng)看下圖
MVP模式示意圖
從上圖可以看出, 從MVC中又抽象出了P層, 即Presenter層
Controller其實(shí)將view和viewController傳遞給了P層, 這樣P層其實(shí)就擁有了控制器的權(quán)利, 完全可以行使控制器的職責(zé).
Controller又持有Presenter, 那么它只需要調(diào)用P層暴露出的接口, 就完全可以完成整個(gè)業(yè)務(wù)邏輯和頁(yè)面展示
關(guān)于C端和P端的循環(huán)引用的問(wèn)題, 直接用weak關(guān)鍵字就可以解決了
利用代碼來(lái)說(shuō)明一下問(wèn)題:
這是一個(gè)Presenter的Protocol, 所有的P層的類都要遵循這個(gè)Protocol
#import /** 作為P : presenter 是管理 view viewController model這個(gè)三個(gè)中間人,負(fù)責(zé)UI刷新 視圖的交互總是和VC 關(guān)聯(lián)著的 */@protocol TGPresenterProtocol @optional// 處理View視圖相關(guān)操作 -- 協(xié)議的遵守者- (void)setView:(NSObject *)view;// 處理事件的相關(guān)響應(yīng)- (void)setViewController:(UIViewController *)viewController;// 展示- (void)present;// 加載model - (void)presentWithModel:(id)model viewController:(UIViewController *)viewController;@end
可以看出, P層是可以拿到view或者viewController的, 并且可以在實(shí)現(xiàn)set方法的時(shí)候做一些事情. 這個(gè)稍后再講
另外, P層還可以展示數(shù)據(jù), 直接展示數(shù)據(jù), present方法, 利用模型展示數(shù)據(jù), 利用presentWithModel:方法
比如, 在一個(gè)遵循了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; // 自適應(yīng)高度 _view.rowHeight = UITableViewAutomaticDimension; _view.estimatedRowHeight = 100; return self;}- (void)setView:(UITableView *)view{ // 設(shè)置視圖 _view = view; _view.delegate = self; _view.dataSource = self; _view.separatorStyle = UITableViewCellSeparatorStyleNone; // 自適應(yīng)高度 _view.rowHeight = UITableViewAutomaticDimension; _view.estimatedRowHeight = 100;}
比如上面的代碼, 將tableView的數(shù)據(jù)源和代理都給了P, 那么P就相當(dāng)于行使了控制器的權(quán)力, 當(dāng)P層拿到數(shù)據(jù)時(shí)(沒(méi)錯(cuò), 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 要處理好數(shù)據(jù)的顯示格式 self.hpModel = [[CellSelfSizeModel alloc] initWithDic:dataDic]; // 刷新 [self present]; }
走Present方法, 實(shí)際就是tableView的reloadData:
- (void)present{[self.view reloadData];}
然后重走tableView的數(shù)據(jù)源方法. 將數(shù)據(jù)分發(fā)給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{// 無(wú)圖片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;}
這樣就實(shí)現(xiàn)了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]; // 視圖對(duì)象 self.hpPresenter.view = self.tableView; // 控制器對(duì)象 self.hpPresenter.viewController = self; // 外邊是要傳入?yún)⑦M(jìn)去的 -- 數(shù)據(jù)模型 [self.hpPresenter loadHPData]; }
只需要初始化P層, 然后調(diào)P層的接口就可以了. 至于P層內(nèi)部的邏輯, 我不需要知道
V層也只專注于視圖的創(chuàng)建
M層只專注于模型的構(gòu)建(字典->模型)
這樣分層, 解耦的思想在程序設(shè)計(jì)中是極為重要的. 其實(shí)也可以看出MVP是對(duì)MVC模式的進(jìn)一步抽象.
代碼Demo是我們老大寫(xiě)的, 我只是分析了一波
來(lái)自:http://www.cocoachina.com/ios/20171106/21062.html
相關(guān)文章:
1. css代碼優(yōu)化的12個(gè)技巧2. 微信開(kāi)發(fā) 網(wǎng)頁(yè)授權(quán)獲取用戶基本信息3. .NET SkiaSharp 生成二維碼驗(yàn)證碼及指定區(qū)域截取方法實(shí)現(xiàn)4. jsp實(shí)現(xiàn)登錄驗(yàn)證的過(guò)濾器5. 詳解瀏覽器的緩存機(jī)制6. jsp EL表達(dá)式詳解7. asp批量添加修改刪除操作示例代碼8. msxml3.dll 錯(cuò)誤 800c0019 系統(tǒng)錯(cuò)誤:-2146697191解決方法9. jsp+servlet簡(jiǎn)單實(shí)現(xiàn)上傳文件功能(保存目錄改進(jìn))10. HTML5 Canvas繪制圖形從入門(mén)到精通
