之前阅读了处理 iOS 中复杂的 Table Views 并保持优雅、iOS:如何构建具有多种 Cell 类型的表视图两篇译文,对于如何处理多类型cell的tableView有不小的收获。但我发现多类型cell的tableView之间也是有区别的。比如译文中就举例实现了动态多类型cell的tableView,这种情况使用MVVM模式有很好的效果。然而我们开发过程中也会有很多静态的多类型cell需要实现,比如微信的个人信息:
这种风格的tableView内容基本是固定且简单,如果要用MVVM去实现会比较繁琐。或者像我之前我都是直接根据indexPath去一一对应生成,这在开发阶段会很快很容易,但是后期如果要修改,比如增加一列或者删除一列,这时候就需要同时修改下面代理中的代码- tableView: numberOfRowsInSection:
- tableView: cellForRowAtIndexPath:
- tableView: didSelectRowAtIndexPath:
复制代码
对于能躺着绝不坐着的个人习惯,我就想是不是可以改进下。
生成model
model的生成大同小异,基本是http获取json后转为model。这里我自己创建了json然后本地获取模拟了下。
{
"photo":"Audrey",
"username":"奥黛丽",
"userCode":"formyicarus222",
"QRCode":"ico",
"sex":1
}
复制代码
model代码:
@interface MultipeTypeModel : NSObject
@property (strong, nonatomic) NSString *photo;
@property (strong, nonatomic) NSString *username;
@property (strong, nonatomic) NSString *userCode;
@property (strong, nonatomic) NSString *qrCode;
@property (assign, nonatomic) NSInteger sex;
+ (void)requestForData:(void(^)(MultipeTypeModel *model))completion;
@end
复制代码
- (instancetype)initWithDict:(NSDictionary *)dict
{
self = [super init];
if (self) {
self.photo = dict[@"photo"];
self.username = dict[@"username"];
self.userCode = dict[@"userCode"];
self.qrCode = dict[@"QRCode"];
}
return self;
}
+ (void)requestForData:(void (^)(MultipeTypeModel * _Nonnull))completion {
NSString *path = [[NSBundle mainBundle] pathForResource:@"MultipleCell" ofType:@"json"];
NSString *json= [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSDictionary *jsonDict = [json jsonValueDecoded];
MultipeTypeModel *model = [[MultipeTypeModel alloc] initWithDict:jsonDict];
completion(model);
}
复制代码
在vc里调用
- (void)geteData {
[MultipeTypeModel requestForData:^(MultipeTypeModel * _Nonnull model) {
self.muModel = model;
}];
}
复制代码
model生成数组
之前我说使用indexPath一一指定的方式去实现有个问题,就是后期需要增加或者删除cell需要修改多处代码。而解决这个问题的办法就是将tableView的数据统一和一个数组关联,那么之后有需求变动,我只需要修改这个数组就可以了。
model转数组代码:
- (NSArray *)tableArrayFromModel:(MultipeTypeModel *)model {
NSArray *arr = @[
@[
@{
@"title":@"头像",
@"image":model.photo?:@"",
@"type":@(MUTableCellTypeHeader),
@"selector":NSStringFromSelector(@selector(doHeaderPhotoAction:))
},
@{
@"title":@"用户名",
@"content":model.username?:@"",
@"type":@(MUTableCellTypeName),
@"selector":NSStringFromSelector(@selector(doUsernameAction:))
},
//
// @{
// @"title":@"性别",
// @"content":model.sex==1?@"男":@"女",
// @"type":@2
// },
@{
@"title":@"微信号",
@"content":model.userCode?:@"",
@"type":@(MUTableCellTypeNameNoAccessory)
},
@{
@"title":@"二维码",
@"image":model.qrCode?:@"",
@"type":@(MUTableCellTypeHeader),
@"selector":NSStringFromSelector(@selector(doQRCodeAction:))
},
@{
@"title":@"更多",
@"content":@"",
@"type":@(MUTableCellTypeName),
@"selector":NSStringFromSelector(@selector(doMoreAction:))
}
],
@[
@{
@"title":@"我的地址",
@"content":@"",
@"type":@(MUTableCellTypeName),
@"selector":NSStringFromSelector(@selector(doAddressAction:))
}
]
];
return arr;
}
复制代码
这是一个二维数组,第一维表示section,第二维表示row。selector
表示点击cell的事件,type
表示cell的类型。cell的类型我是创建一个枚举来指定的:
typedef NS_ENUM(NSInteger,MUTableCellType) {
MUTableCellTypeHeader=1,
MUTableCellTypeName,
MUTableCellTypeNameNoAccessory
};
复制代码
一般来说这种tableView的数据是可以修改的。我按如下思路修改:
1.直接修改self.muModel
实例的属性值。
2.重新将model转为数组
3.reloadData
- (void)reloadTableWithModel:(MultipeTypeModel *)model atIndexPath:(NSIndexPath *)indexPath {
self.tableArray = [self tableArrayFromModel:model];
if (indexPath) {
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else {
[self.tableView reloadData];
}
}
复制代码
tableView根据数组展示
到这里,tableView相关数据就处理完,接下来就是将数据填充进tableView:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *arr = self.tableArray[section];
return arr.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.tableArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *sectionArr = self.tableArray[indexPath.section];
NSDictionary *dict = sectionArr[indexPath.row];
NSInteger type = [dict[@"type"] integerValue];
switch (type) {
case MUTableCellTypeHeader:
{
MUPhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MUPhotoCell" forIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[cell bindDict:dict];
return cell;
}
break;
case MUTableCellTypeName:
{
MUNameCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MUNameCell" forIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
[cell bindDict:dict];
return cell;
}
break;
case MUTableCellTypeNameNoAccessory:
{
MUNameCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MUNameCell" forIndexPath:indexPath];
[cell bindDict:dict];
return cell;
}
break;
default:
break;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:true];
NSArray *sectionArr = self.tableArray[indexPath.section];
NSDictionary *dict = sectionArr[indexPath.row];
NSString *selector = dict[@"selector"];
SEL sel = NSSelectorFromString(selector);
if ([self respondsToSelector:sel]) {
[self performSelector:sel withObject:indexPath];
}
}
复制代码
这样,当我后续接到需求变动,比如上面要添加一个cell,我只需要在- (NSArray *)tableArrayFromModel:(MultipeTypeModel *)model
方法添加一个元素就可以了。
@{
@"title":@"性别",
@"content":model.sex==1?@"男":@"女",
@"type":@(MUTableCellTypeName)
}
复制代码