三月不减肥,六月徒悲伤
最近接手了一个项目,当我打开控制器的时候内心是崩溃的,2000+的代码, WTF?,(自行脑补黑人满脸?表情包),随后的改需求,鬼才知道我经历了什么,所以今天来聊一聊---在使用传统 MVC架构的情况下,如何给控制器的简单瘦身.
胖胖的控制器
为了节省时间,这里我用之前的开源项目来演示,精仿手工课地址源码在最下面,现在我们先来看看效果图
控制器
这是一个简单的界面,采用 UICOllectionView来布局,看一下传统控制器的大概分类
首先是初始化方法
- (instancetype)init
{
// 流水布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
return [self initWithCollectionViewLayout:layout];
}
#pragma mark - 初始化方法
- (void)regisCell
{
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPFairHotCell class]) bundle:nil] forCellWithReuseIdentifier:fariId];
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPFairBestCell class]) bundle:nil] forCellWithReuseIdentifier:fariBestId];
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPFariTopicBestCell class]) bundle:nil] forCellWithReuseIdentifier:fariTopicBestId];
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPFariTopicCell class]) bundle:nil] forCellWithReuseIdentifier:fariTopicId];
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([GPFairSectionHeadView class]) bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:fairHeadID];
}
数据处理
- (void)loadNewData
{
GPFariParmer *parmers = [[GPFariParmer alloc]init];
parmers.c = @"Shiji";
parmers.vid = @"18";
parmers.a = self.product;
__weak typeof(self) weakSelf = self;
[GPFariNetwork fariDataWithParms:parmers success:^(GPFariData *fariData) {
weakSelf.hotArray = [NSMutableArray arrayWithArray:fariData.hot];
weakSelf.bestArray = [NSMutableArray arrayWithArray:fariData.best];
weakSelf.topicBestArray = [NSMutableArray arrayWithArray:fariData.topicBest];
weakSelf.topicArray = [NSMutableArray arrayWithArray:fariData.topic];
GPFariTopicData *topicData = weakSelf.topicArray.lastObject;
weakSelf.lastId = topicData.last_id;
[weakSelf.collectionView reloadData];
[weakSelf.collectionView.mj_header endRefreshing];
} failuer:^(NSError *error) {
[weakSelf.collectionView.mj_header endRefreshing];
[SVProgressHUD showErrorWithStatus:@"啦啦啦,失败了"];
}];
}
- (void)loadMoreData
{
GPFariParmer *parmers = [[GPFariParmer alloc]init];
parmers.c = @"Shiji";
parmers.vid = @"18";
parmers.last_id = self.lastId;
parmers.a = @"topicList";
parmers.page = self.page;
__weak typeof(self) weakSelf = self;
[GPFariNetwork fariMoreDataWithParms:parmers success:^(NSArray *topicDataS) {
[weakSelf.topicArray addObjectsFromArray:topicDataS];
[weakSelf.collectionView reloadData];
[weakSelf.collectionView.mj_footer endRefreshing];
} failuer:^(NSError *error) {
[weakSelf.collectionView.mj_footer endRefreshing];
}];
}
数据源
#pragma mark - UICollectionView 数据源
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return SectionCouton;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
NSInteger rowCount = 0;
if (section == 0) {
rowCount = self.hotArray.count;
}else if (section == 1){
rowCount = self.bestArray.count;
}else if (section == 2){
rowCount = self.topicBestArray.count;
}else{
rowCount = self.topicArray.count;
}
return rowCount;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0){
GPFairHotCell *hotCell = [collectionView dequeueReusableCellWithReuseIdentifier:fariId forIndexPath:indexPath];
hotCell.hotData = self.hotArray[indexPath.row];
return hotCell;
}
else if (indexPath.section == 1){
GPFairBestCell *bestCell = [collectionView dequeueReusableCellWithReuseIdentifier:fariBestId forIndexPath:indexPath];
bestCell.bestData = self.bestArray[indexPath.row];
return bestCell;
}
else if (indexPath.section == 2){
GPFariTopicBestCell *topicBestCell = [collectionView dequeueReusableCellWithReuseIdentifier:fariTopicBestId forIndexPath:indexPath];
topicBestCell.picStr = self.topicBestArray[indexPath.row];
return topicBestCell;
}else{
GPFariTopicCell *topicCell = [collectionView dequeueReusableCellWithReuseIdentifier:fariTopicId forIndexPath:indexPath];
topicCell.topicData = self.topicArray[indexPath.row];
return topicCell;
}
return nil;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
GPFairSectionHeadView *headView = headView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:fairHeadID forIndexPath:indexPath];
if (indexPath.section == 1) {
headView.titleStr = @"每日特价";
headView.subtitleStr = @"每日10:00更新";
}else if (indexPath.section == 2){
headView.titleStr = @"精选专题";
headView.subtitleStr = @"更多";
}
return headView;
}
代理
#pragma mark - UICollectionView 布局
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize size = CGSizeZero;
CGFloat W = 0;
if (indexPath.section == 0) {
W = SCREEN_WIDTH * 0.2;
size = CGSizeMake(W, W * 1.4);
}else if (indexPath.section == 1){
W = SCREEN_WIDTH * 0.27;
size = CGSizeMake(W, W * 2);
}else if (indexPath.section == 2){
W = SCREEN_WIDTH * 0.27;
size = CGSizeMake(W, W);
}else{
W = SCREEN_WIDTH * 0.94;
size = CGSizeMake(W, W * 0.6);
}
return size;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
CGSize size = CGSizeZero;
if (section == 1) {
size = CGSizeMake(SCREEN_WIDTH, GPTitlesViewH);
}else if (section == 2){
size = CGSizeMake(SCREEN_WIDTH, GPTitlesViewH);
}
return size;
}
#pragma mark - UICollectionView 代理
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
if (indexPath.row == 2) {
GPWebViewController *webVC = [UIStoryboard storyboardWithName:NSStringFromClass([GPWebViewController class]) bundle:nil].instantiateInitialViewController;
webVC.hotData = self.hotArray[indexPath.row];
[self.navigationController pushViewController:webVC animated:YES];
}else{
GPTabBarController *tabVc = [[GPTabBarController alloc]init];
tabVc.selectedIndex = 1;
[UIApplication sharedApplication].keyWindow.rootViewController = tabVc;
}
}
else if (indexPath.section == 1){
XWCoolAnimator *animator = [XWCoolAnimator xw_animatorWithType:XWCoolTransitionAnimatorTypePortal];
GPMainWebController *webVc = [UIStoryboard storyboardWithName:NSStringFromClass([GPMainWebController class]) bundle:nil].instantiateInitialViewController;
webVc.bestData = self.bestArray[indexPath.row];
[self xw_presentViewController:webVc withAnimator:animator];
}
else if (indexPath.section == 2){
GPTopicListController *topListVc = [[GPTopicListController alloc]init];
[self.navigationController pushViewController:topListVc animated:YES];
}
else {
XWCoolAnimator *animator = [XWCoolAnimator xw_animatorWithType:XWCoolTransitionAnimatorTypePortal];
GPMainWebController *webVc = [UIStoryboard storyboardWithName:NSStringFromClass([GPMainWebController class]) bundle:nil].instantiateInitialViewController;
webVc.topicData = self.topicArray[indexPath.row];
[self xw_presentViewController:webVc withAnimator:animator];
}
}
从源码可以看出,代码量最大就是数据源和代理,所以如果我们把数据源和代理从控制中剥离出来,那么控制器的代码数量将大大减少,接下来我们正式开始减肥计划
瘦瘦的控制器
控制器
从结构上来看,我们发现数据源和代理失踪了,看看他们去哪了
数据源
.h 声明
typedef void (^CollectionViewCellConfigureBlock)(id cell, id item);
@interface GPFairArrayDataSource : NSObject
// 给 cell 赋值的回调数组
@property (nonatomic, strong) NSArray *cellBlockArray;
// cell 的模型数组
@property (nonatomic, strong) NSArray *cellModeArray;
// cell 的唯一标示符数组
@property (nonatomic, strong) NSArray *CellIDArray;
// 获取当前的模型
- (id)itemAtIndexPath:(NSIndexPath *)indexPath modeArray:(NSArray *)modeArray;
. M 方法的具体实现
@interface GPFairArrayDataSource()
@property (nonatomic, copy) CollectionViewCellConfigureBlock configureCellBlock;
@end
@implementation GPFairArrayDataSource
- (id)itemAtIndexPath:(NSIndexPath *)indexPath modeArray:(NSMutableArray *)modeArray
{
return modeArray[indexPath.row];
}
#pragma mark - UIColltionView 数据源
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return self.cellModeArray.count;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
NSArray *rowArrayCount = self.cellModeArray[section];
return rowArrayCount.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = nil;
NSString *cellIdentifier = self.CellIDArray[indexPath.section];
NSArray *dataArray = self.cellModeArray[indexPath.section];
CollectionViewCellConfigureBlock block = self.cellBlockArray[indexPath.section];
cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath modeArray:dataArray];
block(cell,item);
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
GPFairSectionHeadView *headView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"FairHeadView" forIndexPath:indexPath];
if (indexPath.section == 1) {
headView.titleStr = @"每日特价";
headView.subtitleStr = @"每日10:00更新";
}else if (indexPath.section == 2){
headView.titleStr = @"精选专题";
headView.subtitleStr = @"更多";
}
return headView;
}
接下来,看一下控制器中如何初始化数据源
- (void)setupCollectionView
{
CollectionViewCellConfigureBlock configureHotCell = ^(GPFairHotCell *hotCell,GPFariHotData *hotData){
[hotCell configureForData:hotData];
};
CollectionViewCellConfigureBlock configureBestCell = ^(GPFairBestCell *bestCell,GPFariBestData *BestData){
[bestCell configureForData:BestData];
};
CollectionViewCellConfigureBlock configureTopicBestCell = ^(GPFariTopicBestCell *TopicBestCell,NSString *picStr){
[TopicBestCell configureForData:picStr];
};
CollectionViewCellConfigureBlock configureTopicCell = ^(GPFariTopicCell *topicCell,GPFariTopicData *topicData){
[topicCell configureForData:topicData];
};
self.fairDataSource = [[GPFairArrayDataSource alloc]init];
self.fairDataSource.cellModeArray = @[self.hotArray,self.bestArray,self.topicBestArray,self.topicArray];
self.fairDataSource.CellIDArray = @[fariId,fariBestId,fariTopicBestId,fariTopicId];
self.fairDataSource.cellBlockArray = @[configureHotCell,configureBestCell,configureTopicBestCell,configureTopicCell];
self.collectionView.dataSource = self.fairDataSource;
}