初学UITableView,接触了简单的几个项目,也注意到现在大部分项目都在频繁使用这个控件,其重要程度不言而喻。
UITableView中每个数据往往通过plist来获取,并且通过UITableViewDelegate和UITableViewDataSource这两个协议来完成数据的加载和每一行的样式设计。
其中需要实现的两个必要的协议分别是:
- tableView:numberOfRowsInSection:
- tableView:cellForRowAtIndexPath:
前者规定有多少行数据,后者实现每行数据的加载。
一个标准的有代码复用功能的数据加载如下:
#import "ViewController.h"
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITableView * tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * cellName = @"cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellName];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellName];
}
return cell;
}
@end
对每一行cell的Identifier进缓冲池中找,如果有对应的cell则直接拿来使用,如果没有,就重新创建。
刚开始学习的时候,这段代码几乎就是固定模式了。
但是这样的代码有一些缺陷:
1.代码冗余,一个方法里面牵扯到变量定义,赋值等等,虽然实现功能,却不够简洁。
2.控制器知道的太多了。事实上获取cell的数据只需要获取和传旨两部分,换言之,以最短的两行代码调用实现这个功能,而实现细节最好不要暴露在外部。
上面的缺陷在自定义cell时候尤为体现。
这样就提出了一个封装的需求。
我们把一个cell的数据获取,参数设置都封装在自定义cell内部,而对外部只提供简单的获取cell的方法(一个类方法足以)。
经过优化,我们得到下面代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestTableViewCell * cell = [TestTableViewCell cellWithTableView:tableView];
cell.data = self.data;
return cell;
}
这里我们创建了一个TestTableViewCell的自定义类,它继承自UITableViewCell,用来实现对自定义cell的数据获取和设置。
这里我们没办法看到TestTableViewCell内部是如何实现cell的实力化的,事实上我们也不需要知道,我们需要知道通过这个类的一个类方法cellWithTableView,在传入当前tableView之后就能获取到一个实例化好了的cell。Identifier是对应cell内部自己定义的,我们也不需要去声明和判断。
第二行代码则是对数据的加载,光实例化好了cell还不够,我们需要传值的方式把数据传到自定义cell类中并完成数据的加载。这里我们传入了一个数据模型,具体的加载方式,imageView加载在哪,Label的宽高是多少,都是封装在类内部的,也不是控制器所关心的事情。
最后返回这个cell,大功告成。
同样是设置cell的函数,与上面杂乱的6行代码相比,下面这3行显然要简洁明了很多,并且对代码和功能实现了有效的封装。符合面向对象的编程思想。