在以往的開發(fā)中煮纵,使用MVC架構(gòu)模式的時(shí)候還是居多的,MVC方便的是職責(zé)比較明確偏螺,View負(fù)責(zé)界面的展示行疏,Model存儲(chǔ)數(shù)據(jù)模型,controller負(fù)責(zé)業(yè)務(wù)邏輯套像,原先使用的時(shí)候酿联,Model 使用的是瘦Model的形式,只存儲(chǔ)數(shù)據(jù)模型凉夯,不處理業(yè)務(wù)邏輯货葬,這就導(dǎo)致一個(gè)問題,就是controller的職責(zé)越來越重劲够,需要處理的東西越來越多震桶,包括頁面的構(gòu)建、網(wǎng)絡(luò)請(qǐng)求的處理征绎、頁面的跳轉(zhuǎn)蹲姐,代理方法、響應(yīng)方法等人柿。這樣的結(jié)果是導(dǎo)致controller越來越厚重柴墩,代碼堆積越來越多,少則幾百行代碼凫岖,多則二三千行代碼江咳,這也會(huì)使代碼的后期維護(hù)變得異常艱難,特別是接手別人的代碼哥放,修改bug定位問題會(huì)花費(fèi)更多的時(shí)間歼指,所以我們盡量要從controller抽離一部分的代碼邏輯爹土,為controller瘦身。
一踩身、將View的代碼移到View層
這一方面相信大多數(shù)人做的比較好胀茵,一個(gè)頁面肯定有許多視圖, 以首頁為例子 包括 banner視圖、點(diǎn)擊跳轉(zhuǎn)視圖挟阻、列表視圖琼娘、推薦視圖、尾部視圖附鸽、對(duì)于每一個(gè)模塊的視圖應(yīng)該進(jìn)行子類化封裝脱拼,
#import "HomebannerView.h"
#import "HomeOperationView.h"
#import "HomeMainListView.h"
#import "HomeSecondKillView.h"
#import "HomeTrailsView.h"
然后在控制器中進(jìn)行add
[self.view addSubview:self.containerView];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.bottom.with.offset(0);
}];
[self.containerView addSubview:self.bannerView];
[self.bannerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.offset (0);
make.height.mas_equalTo (143 * KHEIGHT_IPHONE6_SCALE);
}];
//...后續(xù)View的構(gòu)建添加
二、將網(wǎng)絡(luò)請(qǐng)求移動(dòng)到Model層
新的項(xiàng)目之后 拒炎,除了Model挪拟、View、Controller之外击你,我會(huì)單獨(dú)新建一個(gè)ViewModel類玉组,用于處理部分邏輯,在.h文件中將邏輯的方法暴露給controller調(diào)用丁侄,邏輯處理完將 處理結(jié)果回調(diào)給controller進(jìn)行處理
在ViewModel中進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)的獲取以及解析或者后續(xù)的邏輯操作
///IntelGeneDetailViewModel.h 文件
//組合產(chǎn)品是否可投資信息
@property (nonatomic, strong) NSError *investDataError;
@property (nonatomic, strong) InGenDetaiInvestInfoModel *investInfoModel;
@property (nonatomic, assign) BOOL isInvestInfoCompleted;
//請(qǐng)求曲線數(shù)據(jù)
- (void)requestForTrendLineDataWithPortfolioId:(NSString *)portfolioId portfolioType:(NSString *)portfolioType duration:(NSString *)duration;
// 獲得組合產(chǎn)品是否可投資信息
- (void)requestForInvestEnableInfoWithPortfolioId:(NSString *)portfolioId portfolioType:(NSString *)portfolioType content_pk:(NSString *)content_pk;
// IntelGeneDetailViewModel.m 文件
/**
請(qǐng)求組合詳情頁數(shù)據(jù)
*/
- (void)requestForGenDetailDataWithPortfolioId:(NSString *)portfolioId portfolioType:(NSString *)portfolioType {
NSMutableDictionary *dataDic = [NSMutableDictionary dictionary];
[dataDic setObject:portfolioId forKey:@"portfolio_id"];
[dataDic setObject:portfolioType forKey:@"portfolio_type"];
[dataDic addEntriesFromDictionary:self.baseParams];
[dataDic addEntriesFromDictionary:self.userParams];
[[ATTNetwork shareInstance] getWithURL:APIManager.intelGetPortfolioDetailInfo params:dataDic isLoading:YES success:^(id response) {
[self handleIntelGenDetailResponse:response];
} failure:^(NSError *error) {
self.intelGenDetailError = error;
}];
}
- (void)handleIntelGenDetailResponse:(id)response {
response = [Util dictionaryWithJSON:response];
DebugLog(@"組合詳情頁數(shù)據(jù)=%@",response);
BOOL isSuccess = [response[@"is_success"] boolValue];
if (!isSuccess) {
NSString *errorMessage = response[@"error_msg"];
[[UIViewController currentViewController] showToast:errorMessage];
return;
}
NSDictionary *dataDic = response[@"data"];
IntelGenDetailModel *intelGenDetailModel = [IntelGenDetailModel mj_objectWithKeyValues:dataDic];
self.intelGenDetailModel = intelGenDetailModel;
}
處理完的數(shù)據(jù)結(jié)果可以通過 block 惯雳、或者代理等方式回傳給controller做進(jìn)一步的數(shù)據(jù)處理,筆者習(xí)慣使用RAC的方式 在controller 監(jiān)聽 viewModel中值的變化來進(jìn)行值的回傳鸿摇。
//頁面數(shù)據(jù)
[[RACObserve(self.mainViewModel, intelGenDetailError)ignore:nil]subscribeNext:^(NSError *error) {
@strongify(self);
DebugLog(@"錯(cuò)誤代碼=%ld, 錯(cuò)誤描述%@", error.code , error.description);
[self handleNetworkError:error];
}];
[[RACObserve(self.mainViewModel, intelGenDetailModel)ignore:nil]subscribeNext:^(IntelGenDetailModel *model) {
@strongify(self);
self.detailModel = model;
[self handleDataAfterCompleted];
}];
其實(shí)在抽擬的viewModel層不單單可以進(jìn)行網(wǎng)絡(luò)請(qǐng)求石景,還可以進(jìn)行部分邏輯的處理,每個(gè)模塊的高度計(jì)算拙吉,模塊的隱藏與顯示潮孽,跳轉(zhuǎn)的邏輯等等
三、結(jié)構(gòu)復(fù)雜的頁面建議使用child view Controller
如圖的結(jié)構(gòu)頁面
當(dāng)前控制器可以再細(xì)分好幾個(gè)模塊的情況下筷黔,千萬不要幾個(gè)頁面的邏輯操作寫在一個(gè)controller中往史,如果那樣做,那簡直是噩夢(mèng)佛舱。隨著每個(gè)頁面中邏輯和頁面結(jié)構(gòu)的復(fù)雜性椎例,controller中的代碼會(huì)越來越不可控。所以建議一旦一個(gè)頁面下面有明顯的可以細(xì)分的頁面请祖,最好使用child viewController,簡單的邏輯如下
[self addChildViewController:currentVC];
[currentVC didMoveToParentViewController:self];
currentVC.view.frame = CGRectMake(SCREEN_WIDTH * _initiaIndex, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 49 - 64);
[self.pageScrollView addSubview:currentVC.view];
總結(jié)
其實(shí)這些是在項(xiàng)目中使用的最基礎(chǔ)的 Controller 瘦身的一些做法订歪,其實(shí)整個(gè)項(xiàng)目中 用的最多的還是 第一條和第二條的總結(jié),因?yàn)樗械目刂破鞫紩?huì)有這樣的操作肆捕,有時(shí)候都會(huì)在Controller中一不小心就會(huì)寫下幾千行的代碼刷晋,其實(shí)代碼規(guī)范應(yīng)該作為自己的代碼習(xí)慣去遵守,寫出可用性、可讀性的代碼是每個(gè)程序員應(yīng)該做到的眼虱,這樣保證自己項(xiàng)目的可維護(hù)性以及后續(xù)的可擴(kuò)展性或舞,即便是別人接手了你的代碼,至少不會(huì)罵人蒙幻,????。胆筒。邮破。其實(shí)需要Controller瘦身的還有很多,以后項(xiàng)目中會(huì)繼續(xù)總結(jié)仆救。抒和。。彤蔽。