UITableView作為IOS開發的最常用的控件,置信對我們開發來說再熟習不過了,但是越復雜的越熟習的東西,往往也可以看出代碼的質量,項目的構造等問題。本文針對 UITableView中如何順應需求多變(新增刪除、常常互換地位、高度變化等等)的通用處理辦法 及 如何防止同一套完全相反的UITableViewDelegate、UITableViewDataSource代碼在不同UIViewController屢次完成 兩點停止展開討論。缺乏之處還請指正。原文地址
一、UITableView中如何順應需求多變(新增刪除、常常互換地位、高度變化等等)的通用處理辦法拿我擔任的樓盤概況來說:
由於產品會不時的參考運維及競品產品,所以也會不時地對樓盤各個模塊停止迭代調整,假如采用
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
//Dosomething
}
else if (indexPath.row == 1) {
//Dosomething
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
//didSelect
}
else if (indexPath.row == 1) {
//didSelect
}
}
停止代碼兼容,對應的其他辦法也得細心細心是的修正,想想都覺得可怕而又不保險,經過臨時的磨合及疾速順應產品需求而又讓自己身心愉悅,必需得有一套完好而又通用的形式。
遵照一切皆對象的思想方式,我采取了 不同模塊盡量運用獨立的cell
處置,比方
這一塊,盡量分兩個cell完成,畢竟下一次需求 地址
和 最新收盤
就分開了。
當然一個項目最好能有一個基類的UITableViewCell
, 比方這樣的:
@interface FDDBaseTableViewCell<ObjectType>: UITableViewCell
@property (nonatomic,weak) id<FDDBaseTableViewCellDelegate> fddDelegate;
@property (nonatomic,strong) ObjectType fddCellData;
+ (CGFloat)cellHeightWithCellData:(ObjectType)cellData;
- (void)setCellData:(ObjectType)fddCellData;
@end
再者,隨著 MVVM
形式的普及,項目中我也運用了一個兩頭的 cellModel
來控制 UITableView
對 UITableViewCell
的構建:
@interface FDDBaseCellModel : NSObject
@property (nonatomic, strong) id cellData; //cell的數據源
@property (nonatomic, assign) Class cellClass; //cell的Class
@property (nonatomic, weak) id delegate; //cell的代理
@property (nonatomic, assign) CGFloat cellHeight; //cell的高度,提早計算好
@property (nonatomic, strong) FDDBaseTableViewCell *staticCell; //兼容靜態的cell
+ (instancetype)modelFromCellClass:(Class)cellClass cellHeight:(CGFloat)cellHeight cellData:(id)cellData;
- (instancetype)initWithCellClass:(Class)cellClass cellHeight:(CGFloat)cellHeight cellData:(id)cellData;
@end
一套通用構建 UITableView
的大致的思緒如下:
對應的代碼也就是這樣:
- (void)disposeDataSources{
NSArray *randomSources = @[@"Swift is now open source!",
@"We are excited by this new chapter in the story of Swift. After Apple unveiled the Swift programming language, it quickly became one of the fastest groWing languages in history. Swift makes it easy to write software that is incredibly fast and safe by design. Now that Swift is open source, you can help make the best general purpose programming language available everywhere",
@"For students, learning Swift has been a great introduction to modern programming concepts and best practices. And because it is now open, their Swift skills will be able to be applied to an even broader range of platforms, from mobile devices to the desktop to the cloud.",
@"Welcome to the Swift community. Together we are working to build a better programming language for everyone.",
@"– The Swift Team"];
for (int i=0; i<30; i++) {
NSInteger randomIndex = arc4random() % 5;
FDDBaseCellModel *cellModel = [FDDBaseCellModel modelFromCellClass:HDTableViewCell.class cellHeight:[HDTableViewCell cellHeightWithCellData:randomSources[randomIndex]] cellData:randomSources[randomIndex]];
[self.dataArr addObject:cellModel];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.dataArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
FDDBaseCellModel *cellModel = self.dataArr[indexPath.row];
FDDBaseTableViewCell *cell = [tableView cellForIndexPath:indexPath cellClass:cellModel.cellClass];
[cell setCellData:cellModel.cellData delegate:self];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
FDDBaseCellModel *cellModel = self.dataArr[indexPath.row];
//Dosomething
}
也就是無論有多少種不同類型、各種順序陳列的 UITableViewCell
,我們只需求關注數據源中的FDDBaseCellModel即可 ,而且 UITableViewDataSource
中的協議辦法變得極為的簡約和通用。
有了後面的設想,我們會驚奇的發現,完成一個無論復雜或許復雜的 UITableView
僅僅取決於包括 FDDBaseCellModel
的數據源!而一切包括 UITableView
的 UIViewController
的 UITableViewDelegate、UITableViewDataSource
代碼完全分歧!
那麼問題來了,怎樣防止有如此的的反復代碼在你優秀的項目中呢?
1、承繼幫你忙:在項目的 UIViewController
基類中,完成通用的 UITableViewDelegate、UITableViewDataSource
辦法即可,畢竟數據源 self.dataArr
可以放在基類中,子類假如的確有通用辦法無法處置的特殊狀況,沒有問題!各自子類重載對應的辦法即可。Objective-C
和 Swift
通用。
存在的問題:
1. 對非承繼基類的 UIViewController 有力回天;
2. 對 UIView 中包括的 UITableView 無法做到兼容;
3. 當 UITableViewDelegate、UITableViewDataSource不是交給以後 UIViewController 時;
4. 等等等。。。
2、兩頭轉換類(FDDTableViewConverter)完成:
2.1、經過呼應形式來完成:
只需求判別 UITableView
的載體能否能呼應對應的 UITableViewDelegate、UITableViewDataSource
辦法,假如載體完成則運用載體自身的辦法即可,這個其實和承繼中重載的思緒分歧,但是少了一層承繼依賴關系總是好的。Swift
不可用。
存在的問題:
1. 和承繼方式一樣,需求在以後類呼應 UITableViewDelegate、UITableViewDataSource 辦法;
2. 當 UITableViewDelegate、UITableViewDataSource 不是交給以後 UIViewController 時;
3. 由於載體不在遵照 UITableViewDelegate、UITableViewDataSource,寫對應的辦法是編譯器無法給到代碼聯想補全功用,略為難。
4. 兩頭轉換類需求完成大局部的 UITableViewDelegate、UITableViewDataSource 辦法,盡量片面寫完;
5. 呼應形式中由於要在 轉換類 中調用載體的辦法、提供不定向的入參及接納前往值,運用 performSelector: 辦法則不可行,在 Objective-C 中倒是可以運用 NSInvocation 完成,但是在 Swift 中 NSInvocation 曾經被廢棄,也就是只能兼容 Objective-C 代碼。假如有其他方式兼容 swift 請立馬告知我,謝謝!
6. 等等等。。。
2.2、經過注冊形式來完成:
這種思想形式和AOP切片形式很像,哪裡注冊了 UITableViewDelegate、UITableViewDataSource
辦法,哪裡處置改辦法,沒有默許的一致走 兩頭轉換類 的一致處置。完成方式是經過 NSMutableDictionary
來保管注冊的 SEL
和 resultBlock
。resultBlock
傳參放入一個數組中,個數和 SEL
中的入參堅持分歧,前往值是注冊的載體前往給 兩頭轉換類 的後果, 兩頭轉換類 拿到這個值再給到 UITableViewDelegate、UITableViewDataSource
。仿佛有點轉,看代碼你一定就明晰了:
FDDTableViewConverter
局部代碼:
typedef id (^resultBlock)(NSArray *results);
@interface FDDTableViewConverter<TableViewCarrier>: NSObject <UITableViewDataSource, UITableViewDelegate>
//默許形式,運用注冊方式處置tableView的一些協議
@property (nonatomic, assign) FDDTableViewConverterType converterType;
// 只要在選擇 FDDTableViewConverter_Register 形式時,才會block回調
- (void)registerTableViewMethod:(SEL)selector handleParams:(resultBlock)block;
@end
UITableView
載體 ViewController
局部代碼:
- (void)disposeTableViewConverter{
_tableViewConverter = [[FDDTableViewConverter alloc] initWithtableViewCarrier:self daraSources:self.dataArr];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.delegate = _tableViewConverter;
tableView.dataSource = _tableViewConverter;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:tableView];
__weak typeof(self) weakSelf = self;
[_tableViewConverter registerTableViewMethod:@selector(tableView:cellForRowAtIndexPath:) handleParams:^id(NSArray *results) {
UITableView *tableView = results[0];
NSIndexPath *indexPath = results[1];
FDDBaseCellModel *cellModel = weakSelf.dataArr[indexPath.row];
FDDBaseTableViewCell *cell = [tableView cellForIndexPath:indexPath cellClass:cellModel.cellClass];
[cell setCellData:cellModel.cellData delegate:weakSelf];
return cell;
}];
}
這種方式暫時看來是比擬可取的方式了,無論從代碼的整潔還是耦合度來說都是十分棒的形式了,而且它關注的是誰注冊了對應的辦法,你就在block拿到 兩頭轉換類 的值來完成你特殊化的 UITableView
, 再回傳給 兩頭轉換類 來替你完成。而且注冊的 SEL
有代碼聯想補全功用,Objective-C
和 Swift
通用。
存在的問題:
1. 兩頭轉換類需求完成大局部的 UITableViewDelegate、UITableViewDataSource 辦法,盡量片面寫完。
2. 等等等。。。
3、Swift經過Category完成:
Swift
和 Objective-C
的 Category
完成機制是不一樣的,關於 Objective-C
來說,以後類和 Category
有相反辦法時會優先執行 Category
中的辦法,但是在 Swift
的世界裡,同時存在同一個辦法是不允許的,所以也就多了一個 override
關鍵字來優先運用以後類的辦法。
完成方式也就是在 UITableView
載體的 Category
中完成通用的代碼,然後運用 override
關鍵字來特殊化需求特殊處置的 辦法即可。
比方這樣:
FDDTableViewConverter.swift
extension FDDBaseViewController: FDDBaseTableViewCellDelegate {
@objc(tableView:numberOfRowsInSection:) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArr.count
}
@objc(tableView:cellForRowAtIndexPath:) func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellModel: FDDBaseCellModel = self.dataArr.object(at: indexPath.row) as! FDDBaseCellModel
let cell: FDDBaseTableViewCell = tableView.cellForIndexPath(indexPath, cellClass: cellModel.cellClass)!
cell.setCellData(cellModel.cellData, delegate: self)
cell.setSeperatorAtIndexPath(indexPath, numberOfRowsInSection: self.dataArr.count)
return cell
}
@objc(tableView:heightForRowAtIndexPath:) func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cellModel: FDDBaseCellModel = self.dataArr.object(at: indexPath.row) as! FDDBaseCellModel
return CGFloat(cellModel.cellHeight)
}
}
ViewController.swift
override internal func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
這種形式代碼量十分少,並且完成起來很方便,Objective-C
不可用。
存在的問題:
1. 當在引入 FDDTableViewConverter.swift 後,由於Swift項目的特殊性(同模塊中不需求導入該文件即可運用),這會招致以前的代碼中,不是通用代碼能完成的 UITableViewDelegate、UITableViewDataSource 辦法後面都得加上 override 關鍵字;
2. 和承繼有異樣的缺點,不同的載體需求寫上對應的category,貌似這塊代碼又是反復代碼,苦逼;
3. 等等等。。。
三、小結:
下面的兩個問題點是同事 @袁強 拋出給到我,但是處理問題的思緒很多出至於 @凌代平 ,很慶幸有這麼一次時機來碼磚的時機。置信還會有其他更好的思緒,假如你正美觀到了請不吝賜教,
代碼整潔的路途很遠,我置信只需需求了解到位,代碼設計合理,我置信當前我們的完成 UITableView
時,只需求如下代碼:
@implementation ViewController
- (void)dealloc{
NSLog(@"%@ dealloc", NSStringFromClass(self.class));
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"ViewController";
[self disposeDataSources];
[self disposeTableViewConverter];
}
- (void)disposeDataSources{
NSArray *randomSources = @[@"Swift is now open source!",
@"We are excited by this new chapter in the story of Swift. After Apple unveiled the Swift programming language, it quickly became one of the fastest groWing languages in history. Swift makes it easy to write software that is incredibly fast and safe by design. Now that Swift is open source, you can help make the best general purpose programming language available everywhere",
@"For students, learning Swift has been a great introduction to modern programming concepts and best practices. And because it is now open, their Swift skills will be able to be applied to an even broader range of platforms, from mobile devices to the desktop to the cloud.",
@"Welcome to the Swift community. Together we are working to build a better programming language for everyone.",
@"– The Swift Team"];
for (int i=0; i<30; i++) {
NSInteger randomIndex = arc4random() % 5;
FDDBaseCellModel *cellModel = [FDDBaseCellModel modelFromCellClass:HDTableViewCell.class cellHeight:[HDTableViewCell cellHeightWithCellData:randomSources[randomIndex]] cellData:randomSources[randomIndex]];
[self.dataArr addObject:cellModel];
}
}
- (void)disposeTableViewConverter{
_tableViewConverter = [[FDDTableViewConverter alloc] initWithtableViewCarrier:self daraSources:self.dataArr];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.delegate = _tableViewConverter;
tableView.dataSource = _tableViewConverter;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:tableView];
}
@end
Objective-C源碼地址
Swift源碼地址
歡送 star
【UITableView怎樣開啟極簡形式】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!