你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> UITableView怎樣開啟極簡形式

UITableView怎樣開啟極簡形式

編輯:IOS開發綜合

UITableView作為IOS開發的最常用的控件,置信對我們開發來說再熟習不過了,但是越復雜的越熟習的東西,往往也可以看出代碼的質量,項目的構造等問題。本文針對 UITableView中如何順應需求多變(新增刪除、常常互換地位、高度變化等等)的通用處理辦法 及 如何防止同一套完全相反的UITableViewDelegate、UITableViewDataSource代碼在不同UIViewController屢次完成 兩點停止展開討論。缺乏之處還請指正。原文地址

一、UITableView中如何順應需求多變(新增刪除、常常互換地位、高度變化等等)的通用處理辦法

拿我擔任的樓盤概況來說:

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 處置,比方

UITableView怎樣開啟極簡模式

這一塊,盡量分兩個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 來控制 UITableViewUITableViewCell 的構建:

@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 的大致的思緒如下:

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 中的協議辦法變得極為的簡約和通用。

二、如何防止同一套完全相反的UITableViewDelegate、UITableViewDataSource代碼在不同UIViewController屢次完成

有了後面的設想,我們會驚奇的發現,完成一個無論復雜或許復雜的 UITableView 僅僅取決於包括 FDDBaseCellModel 的數據源!而一切包括 UITableViewUIViewControllerUITableViewDelegate、UITableViewDataSource 代碼完全分歧!

那麼問題來了,怎樣防止有如此的的反復代碼在你優秀的項目中呢?

1、承繼幫你忙:

在項目的 UIViewController 基類中,完成通用的 UITableViewDelegate、UITableViewDataSource 辦法即可,畢竟數據源 self.dataArr 可以放在基類中,子類假如的確有通用辦法無法處置的特殊狀況,沒有問題!各自子類重載對應的辦法即可。Objective-CSwift 通用。

存在的問題:

1. 對非承繼基類的 UIViewController 有力回天;
2. 對 UIView 中包括的 UITableView 無法做到兼容;
3. 當 UITableViewDelegate、UITableViewDataSource不是交給以後 UIViewController 時;
4. 等等等。。。
2、兩頭轉換類(FDDTableViewConverter)完成:

UITableView怎樣開啟極簡模式

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 來保管注冊的 SELresultBlockresultBlock 傳參放入一個數組中,個數和 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-CSwift 通用。

存在的問題:

1. 兩頭轉換類需求完成大局部的 UITableViewDelegate、UITableViewDataSource 辦法,盡量片面寫完。
2. 等等等。。。
3、Swift經過Category完成:

SwiftObjective-CCategory 完成機制是不一樣的,關於 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怎樣開啟極簡形式】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved