前言:笔者刚工作不久、而且是和一个即将离职的同事做工作交接。所以工作两个月以来基本都是在修前人的代码。然后、出现了这样一个问题。
没错、我们的页面有很多格式相似需要统一配置的列表、而截图只是其中一小部分。笔者一开始对结构项目不熟、UI也是刚来没多久。所以在UI提出新改动的时候、出现了很多次个别页面漏改的情况(footer底色啊、高度啊、下方分割线是否显示啊之类0.0)。需求改一点、就要把每个VC里的tb设置全部都改一遍实在是心累~
再然后、项目里的商品详情、也分出了三个模式
没错、每个模式列表的样式又有着些许的差别。于是乎项目里又出现了各种判断~
暂时这样写问题不大、但是想想、将来需求累加起来。单一模式的布局一改、就开始复杂了。
恰巧前阵子在看网络层架构、感受到了很多NetworkManager的好处。所以想试试能不能通过一个统一的列表管理器(ListManager)来统一调配项目中大部分风格一致的列表。于是、就有了以下的尝试。
——————————————正文——————————————————
以下、笔者只大概提出思路。毕竟对于菜鸡、言多必失。
1、ListManager
既然是Manager、必然要起到管理器的作用。
1.1 配置统一的tableView
要把尽量多的配置、交付给Manager、从而减轻了VC的压力。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//实现代理方法以代理方法为准
if ([self.delegate respondsToSelector:@selector(LMnumberOfSectionsInTableView:)]) {
return [self.delegate LMnumberOfSectionsInTableView:tableView];
}
//否则以默认为准
return Y;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//可以根据VM配置、也可以手动配置
if ([self.delegate respondsToSelector:@selector(LMtableView:numberOfRowsInSection:)]) {
return [self.delegate LMtableView:tableView numberOfRowsInSection:section];
}
return X;
}
1.2 暴露代理API给VC、以备不时之需。上面的判断、就是那个意思。这样我们在控制器中实现之后、就可以覆盖manager中的原装设置
/* 暴露tableView代理方法至listManager所依赖控制器 */
- (NSInteger)LMnumberOfSectionsInTableView:(UITableView *)tableView;
- (CGFloat)LMtableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSInteger)LMtableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UIView *)LMtableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
- (UIView *)LMtableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
。。。。。。。。
1.3 cell配置的实现
既然是统一配置、必然不可能把每个cell写进来所以、我们需要一个协议、用来约束cell。当然、下面的参数并不是充要条件、我只是copy了自己demo里的代码
@protocol BaseListManagerCellDelegate <NSObject>
@optional
/**
* 配置cell统一方法
* @param model ListVM
* @param indexPath indexPath
* @param target cell事件代理 将cell协议事件统一交由listmanager的代理实现
* 如果cell需要代理回调事件、务必设置listmanager代理
*/
- (void)configurationCellWithModel:(BaseListModel*)model indexPath:(NSIndexPath *)indexPath target:(id)target;
于是乎、在所需cell遵循了协议之后、我们可以在ListManger中直接通过协议配置cell、如此这般
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Manager所属cell必须遵循协议。实现配置方法
//@"cellID"是我们在VC中需要做的、注册cell给manager
UITableViewCell<BaseListManagerCellDelegate> * cell = [tableView dequeueReusableCellWithIdentifier:@"cellID"];
// 通过协议方法配置cell
[cell configurationCellWithModel:model indexPath:indexPath target:self.delegate];
return cell;
}
2、ListModel
其实这个Model可有可无。如果你习惯FatModel或者MVVM。可以尝试添加进去如果公司的网络层统一度比较不错。简单页面用用、还是挺省事的
内部就不写了~毕竟每个公司网络架构都不同。心意到了就好。同样是copy的demo、不要太在意细节0.0
@interface BaseListModel : NSObject
@property (nonatomic) NSMutableArray *dataArray;
//关于数据源~我不是很喜欢里面放一个个model。不过放啥都无所谓了。不是重点呗~
@property (nonatomic) NSInteger page;
/* 请求url */
@property (nonatomic) NSString *dataUrl;
/* 删除url 不传入则不具备删除功能 */
@property (nonatomic) NSString *deleteDataUrl;
/* 删除的key 需要删除功能时必须传入*/
@property (nonatomic) NSString *deleteKey;
/**
* 翻页
*/
- (void)next;
/**
* 刷新
*/
- (void)freshenDataArray;
/**
* 删除
*
* @param integer 数据位置
*/
- (void)deleteDataArrayAtIndex:(NSInteger)integer;
哦对~ListModel在实际的使用中、还可以暴露出几个API。毕竟很多时候在请求之后、页面还需要不同的提示啊、之类么0.0
@protocol KiritoListModelDelegate <NSObject>
@optional
/**
* 刷新开始前代理
*
* @return 继续执行model方法返回Yes 屏蔽返回No
*/
- (BOOL)modelBegainLoadDate;
- (void)modelEndLoadDate:(NSDictionary *)json;
/**
* 删除开始前代理
*
* @return 继续执行model方法返回Yes 屏蔽返回No
*/
- (BOOL)modelBegainDeleteDataAtIndex:(NSInteger)index;
- (void)modelEndDeleteData:(NSDictionary *)json;
想不起来还应该交待点什么、干脆再重申一次。FatModel并不是充要条件。
3、使用
我也不知道该说啥~反正感觉不太难0.0。贴一个项目里的使用吧
嗯、只需要配置一些充要条件。除非有什么特殊需求需要用API颠覆manger的配置。不然就不再用写啥了
4、总结
这并不是我造的轮子、充其量是一个思想而已。
我想解决的问题:(其实就是前言里写的状况~)
第一、既然网络层可以通过manager统一设置、为什么表现层的列表们不去交给相应的manager统一配置、每天搞很多重复工作真的很累。一旦UI有新Idea、真的很累、真的...
第二、一旦同一个页面有太多不同的模式。与其在cellForRow/height/footer/header里写很多判断。何不干脆单独写出三个manager。通过为VC装载不同的manager实现不同的页面配置。(对~这里就是组合)
4、最后
第一次写博客、不知道有没有阐述明白。如果哪里不对、望轻拍。我会虚心接受的。
所以、还是贴demo吧~OC的Demo写的乱七八糟、而且没有注释。所以、Demo是Swift的、看看注释就好了。
下载链接