以前閱讀了處理 iOS 中複雜的 Table Views 並保持優雅、iOS:如何構建具備多種 Cell 類型的表視圖兩篇譯文,對於如何處理多類型cell的tableView有不小的收穫。但我發現多類型cell的tableView之間也是有區別的。好比譯文中就舉例實現了動態多類型cell的tableView,這種狀況使用MVVM模式有很好的效果。然而咱們開發過程當中也會有不少靜態的多類型cell須要實現,好比微信的我的信息: json
這種風格的tableView內容基本是固定且簡單,若是要用MVVM去實現會比較繁瑣。或者像我以前我都是直接根據indexPath去一一對應生成,這在開發階段會很快很容易,可是後期若是要修改,好比增長一列或者刪除一列,這時候就須要同時修改下面代理中的代碼- tableView: numberOfRowsInSection:
- tableView: cellForRowAtIndexPath:
- tableView: didSelectRowAtIndexPath:
複製代碼
對於能躺着毫不坐着的我的習慣,我就想是否是能夠改進下。數組
model的生成大同小異,基本是http獲取json後轉爲model。這裏我本身建立了json而後本地獲取模擬了下。bash
{
"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裏調用post
- (void)geteData {
[MultipeTypeModel requestForData:^(MultipeTypeModel * _Nonnull model) {
self.muModel = model;
}];
}
複製代碼
以前我說使用indexPath一一指定的方式去實現有個問題,就是後期須要增長或者刪除cell須要修改多處代碼。而解決這個問題的辦法就是將tableView的數據統一和一個數組關聯,那麼以後有需求變更,我只須要修改這個數組就能夠了。ui
model轉數組代碼:atom
- (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的類型我是建立一個枚舉來指定的:spa
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:code
- (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)
}
複製代碼