這兩天時(shí)間寬松一點(diǎn)蟋座,所以我也來(lái)學(xué)學(xué)MVP的設(shè)計(jì)模式拗踢,有人說(shuō)是架構(gòu),管他呢向臀,好用就行巢墅。so,開(kāi)干券膀! 后邊有OC版本的demo
- 打開(kāi)了Google君纫,搜了一下關(guān)鍵字 MVP iOS,然后發(fā)現(xiàn)了一些文章芹彬,最后是這篇文章帶給我對(duì)MVP 的一些認(rèn)識(shí)蓄髓。
- 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)能力
如下
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ù)邏輯侧蘸。
- 說(shuō)啥都是廢話(huà)裁眯,交出代碼,我們還能做朋友
首先看下結(jié)構(gòu)
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--------