iOS - TableViewCell(CollectionVi
一. 声明:
在此文章中以tableView举例, 便于描述.
二. 问题提出:
通常我们在写一个tableView时候, 在其协议方法:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
在其中会创建多种cell或者从重用池中取出多种cell, 而通常使用index进行判断, 什么时候用哪种cell, 如果这个页面cell的种类少倒还好, 可是如果cell种类繁杂, 那么在这个协议方法中的判断那真是非常折磨人的, 所以参照一些资料, 想出这个cell 的工厂模式.
三. 想法:
所谓的工厂模式, 咱们可以这么理解, 一个工厂就是一个加工车间, 如图所示, 送进去原料, 在工厂中进行一系列加工处理, 然后生产出产品.
用在此处就体现出了面向对象的两个特性: 继承和多态. 我们用同样的思维来思考cell工厂的模式, 我们需要原料, 送进CellFactory, 然后得到对应种类的cell.
四. 思路:
同理, 通过数据转化成Model, 再由tableViewCell呈现到界面给用户(CollectionView同理).我们得知道自己需要什么, 当然工厂的产品应该是不同种类的cell, 那么他的原料也应该是不一样的, 那cell种类和什么东西是一一对应的呢, 显而易见是不同种类的model, 这样我们基本的思路就成型了, 创建一个cellFactory, 放入Model, 进行处理, 生成cell
CellFactory示意图.png
五. 实现过程:
- 第一步:创建基类BaseTableViewCell, 继承于UITableViewCell,
在BaseTableViewCell.h中声明方法:
// 赋值方法(在父类实现, 在子类中重写)
-(void)setModel:(__kindof BaseModel *)model;
在BaseTableViewCell.m中实现方法:
-(void)setModel:(__kindof BaseModel *)model {
}
- 第二步:创建model的基类BaseModel, 继承于NSObject
在BaseModel.h中声明方法
+(instancetype)modelWithDictionary:(NSDictionary *)dic;
在BaseModel.m中实现方法
-(void)setValue:(id)value forKey:(NSString *)key {
[super setValue:value forKey:key];
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
[super setValue:value forUndefinedKey:key];
}
-(id)valueForUndefinedKey:(NSString *)key {
return nil;
}
-(instancetype)initWithDictionary:(NSDictionary *)dic {
self = [super init];
if (self) {
[self setValuesForKeysWithDictionary:dic];
}
return self;
}
+(BaseModel *)modelWithDictionary:(NSDictionary *)dic {
return [[self alloc] initWithDictionary:dic];
}
- 第三步:创建model: StudentModel, 继承于BaseModel
//写对应的属性, 此处为了简单只写了一个name
@property (nonatomic, copy) NSString *name;
- 第四步: 创建tableViewCell: StudentTableViewCell, 继承于BaseTableViewCell
这里为了方便直接使用xib铺了一个Label, 并重写BaseTableView中的赋值方法:
-(void)setModel:(StudentModel *)model {
[super setModel:model];
_nameLabel.text = model.name;
}
StudentTableViewCell.png
- 第五步: 创建一个工厂类, LTQCellFactory
在LTQCellFactory.h中声明:
+(BaseTableViewCell *)createTableViewCellWithModel:(BaseModel *)model
tableView:(UITableView *)tableView;
在LTQCellFactory.m中实现:
+(BaseTableViewCell *)createTableViewCellWithModel:(BaseModel *)model
tableView:(UITableView *)tableView {
NSString *modelName = [NSString stringWithUTF8String:object_getClassName(model)];
NSString *classNameOfCell = [[modelName substringToIndex:modelName.length - 5] stringByAppendingString:@"TableViewCell"];
BaseTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:classNameOfCell];
return cell;
}
- 第六步:引入头文件后,注册Cell并在ViewController中实现
// 注册StudentTableViewCell
[_tableView registerNib:[UINib nibWithNibName:@"StudentTableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"StudentTableViewCell"];
// 在tableView协议方法中实现
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BaseModel *model = _dataArr[indexPath.row];
BaseTableViewCell *cell = [LTQCellFactory createTableViewCellWithModel:(BaseModel *)model tableView:tableView];
[cell setModel:model];
return cell;
}
补充: 由于我自己写的CellFactory是用model的Classname与Cell的Classname进行关联的, 所以在给model和cell的类起名字的时候, 一定要注意, model类名一定要为XXXModel, 而对应的Cell名一定要为XXXTableViewCell或XXXCollectionViewCell,
而在注册的时候直接用cell的类名作为cell在重用池中的重用标识
例如:
起名问题.png
结论: 这样一来可以在这个dataSource的协议方法中可以节省大量的判断和其他操作过程, 运用了继承和多态, 使得代码更加整洁, 并且高大上了有木有, 如果有问题欢迎留言讨论, 如果我写的文章对你有帮助别忘记点个赞哦😯