之前閱讀了處理 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)
}
複製程式碼