前言
UITableView(UITableViewController)是iOS开发使用频率最高的一个组件。
不管是使用UITableView还是还是UITableViewController,在开发的时候,我们都需要实现两个协议:
UITableViewControllerDataSource
UITableViewControllerDelegate
这两个协议的代码不是写在Controller里就是写在ViewModel里,并且这些方法很难复用。关于Controller瘦身的更多细节,可以参我之前的一篇博客:
是否有一种更好的方式来开发TableView呢?如果是Model驱动,而不是代理方法驱动的就好了,如果是Model驱动,开发的时候只需要:
- 创建Row和Section对应的Model
- 由一个Manager去管理这些Model,并且对Client隐藏DataSource和Delegate方法
- 把TableView绑定到Manager
基于这些理念,开发了一个model-driven-tableView框架,
问题
重复代码
Delegate/DataSource中,有许多重复的代码。比如:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _dataArray.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 80.0;
}
这些代码的逻辑其实是一样的,一个section,一个数组作为Model,row的数量就是数组元素的个数。但是,很多时候我们都是在一个一个Controller之间进行copy/paste。
Render代码
通常,在cellForRowAtIndexPath
或者willDisplay
中,我们会对Cell进行重新配置,保证cell在复用的时候显示正确。于是,对Cell进行配置的代码耦合到了ViewController里,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
YourCustomCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[YourCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
cell.leftLabel.text = titleArray[indexPath.row];
cell.infoIcon.image = [UIImage imageNamed:imageArray[indexPath.row]];
cell.rightLabel.text = rightArray[indexPath.row];
return infoCell;
}
大量的if/else
当Cell的种类多了起来,或者点击cell的动作复杂起来,你会发现代码里充斥着各种各样的if/else(switch也一样)。大量的if/else导致代码难以阅读和维护。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
}else if(section == 1){
}else{
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
}else if(indexPath.section == 1){
}else{
}
}
这种情况,在设置界面尤其明显,比如这是网易云音乐的设置界面:
思考一下,如果让你来写,你会怎么写?
解决方案
基类
继承是一个实现代码复用的解决方案,通过在基类中实现-子类重写的方式进行服复用。
比如:
@interface SingleSectionTableViewController : UITableViewController
@property (strong, nonatomic)NSMutableArray * dataArray;
@end
@implementation SingleSectionTableViewController
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[NSException raise:@"Com.t