- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.section == 0) {
if (_viewModel.goodsInfo.count == 1) {
} else {
if(indexPath.row == 0) {
} else if(indexPath.row == _viewModel.goodsInfo.count - 1) {
} else {
}
}
return cell;
} else if (indexPath.section == 1 ) {
switch (indexPath.row) {
case 0:
{
}
break;
case 1:
{
}
break;
case 2:
{
}
break;
case 3:
{
}
break;
default:
break;
}
return cell;
} else if (indexPath.section == 2 ) {
} else if (indexPath.section == 3 ) {
} else if (indexPath.section == 4 ) {
} else if (indexPath.section == 5 ) {
}
return [UITableViewCell new];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.section == 0) {
if (_viewModel.goodsInfo.count == 1) {
} else {
if(indexPath.row == 0) {
} else if(indexPath.row == _viewModel.goodsInfo.count - 1) {
} else {
}
}
return cell;
} else if (indexPath.section == 1 ) {
switch (indexPath.row) {
case 0:
{
}
break;
case 1:
{
}
break;
case 2:
{
}
break;
case 3:
{
}
break;
default:
break;
}
} else if (indexPath.section == 2 ) {
} else if (indexPath.section == 3 ) {
} else if (indexPath.section == 4 ) {
} else if (indexPath.section == 5 ) {
}
}
先贴一篇完全使用indexPath.row .section 实现的cell返回和点击事件的代码。每个iOS开发基本都写过,也看别个写过。如果cell过多,这种代码首先不说看着恼火,这样写法如果涉及改动更是让人头大,稍不注意就埋bug了。
数数这样写法的三宗罪:
1. indexPath不包含任何业务逻辑,阅读逻辑困难
2. indexPath判断逻辑固定,改动牵一发动全身,改动风险大
3. indexPath判断嵌套以及固定写法,基本无法做到界面动态变化,即使强行做到也是史诗级灾难。
作为一个对代码质量有点要求的程序员,也为了便于后期维护保养,以及为了防止别人改你代码问候你祖宗十八代。我们应该告别这种写法,毕竟利己利民。。
如何改进
首先这种tableview主要出现在一些详情显示界面,表单输入界面等。界面有不同的cell,而数据源一般只有一个。 不同于我们写的一些涉及上拉刷新,下拉加载的界面,数据源是一个数组,cell复用时根据indexpath从数据源中取出模型,给cell设置不同的显示值,但是这其中体现了一个苹果的设计思想,cell的不同显示根本上是通过数据源控制的,不是通过indexpath控制的,总结来说就是用数据源控制界面显示
。
有了数据源控制界面显示这个思想,我们可以想到怎么重构上述的代码,cell该怎么排列,cell的返回,cell高度的返回,cell的点击事件等等应该有数据源来控制。
比如一个界面布局如下,=分割代表了不同的section
=======
[标题cell]
[内容cell]
=======
[推荐cell]
[评论输入cell]
=======
[举报cell]
1.我们的数据源可以设置为这些cell对应的业务的数组。
我一般习惯设置对应的枚举,方便使用switch,用字符串也可以。
typedef NS_ENUM(NSInteger, DemoCellType) {
DemoTitleType,
DemoContentType,
DemoRecommendType,
DemoInputType,
DemoReportType
};
2.构建数据源
如果是带section的界面,就构建二维数组
self.dataArray = @[@[@(DemoTitleType),@(DemoContentType)],
@[@(DemoRecommendType),@(DemoInputType)],
@[@(DemoReportType)]];
3.实现tableview代理事件
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DemoCellType type = [self.dataArray[indexPath.section][indexPath.row] integerValue];
DemoBaseCell *cell;
switch (type) {
case DemoTitleType:
cell = [tableView dequeueReusableCellWithIdentifier:@"DemoTitleTypeCellId" forIndexPath:indexPath];
break;
case DemoContentType:{
cell = [tableView dequeueReusableCellWithIdentifier:@"DemoContentTypeCellId" forIndexPath:indexPath];
}
break;
/**
other
*/
default:
break;
}
cell.model = self.model;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DemoCellType type = [self.dataArray[indexPath.section][indexPath.row] integerValue];
DemoBaseCell *cell;
switch (type) {
case DemoTitleType:
break;
case DemoContentType:{
}
break;
/**
other
*/
default:
break;
}
}
/**
返回高度等
*/
到这里,核心代码基本实现完毕。
我们可以看是否解决了之前代码的三宗罪
1. cell的返回,点击等代理方法里都是通过具体的业务做的判断,逻辑清晰。
2. 因为根据业务判断,而不是indexPath,业务上增加或减少cell,只需要数据源增删,和代理方法里任意位置插入对应的判断和实现即可,不会影响之前的代码,甚至不用阅读之前的代码逻辑。不会像最开始代码写法要去考虑增删了cell后,要去修改所有相关indexPath的判断。
3. 数据源控制界面显示,cell顺序改变,隐藏,显示,只用操作数据源元素的增、删、移后,reload即可,让服务器随意动态配置我们的界面显示提供了可能。不用关注和修改tableview代理方法。