iOS回顧筆記(07) -- UITableView的使用和性能優化

iOS回顧筆記(07) -- UITableView的使用和性能優化

若是問iOS中最重要的最經常使用的UI控件是什麼,我以爲UITableView當之無愧!彷佛全部常規APP都使用到了UITableView。下面就講一講UITableView的經常使用知識和使用原理及性能優化!css

1.簡介

  • UITableView故名思議是一種表格控件,是iOS應用中經常使用的表格控件。常見UITableView如圖:

  • UITableView繼承於UIScrollview,所以它默認支持垂直滾動(只支持垂直滾動)html

  • UITableView性能極佳,它能夠出色的完成咱們工做中的不少功能。nginx

  • UITableView一共有兩種樣式:UITableViewStylePlain 和 UITableViewStyleGroupweb

效果分別如圖:
canvas

 

UITableViewStylePlain:一種平鋪的效果,而且分組組頭默認有停靠效果;緩存

UITableViewStyleGroup:一種組間分離的效果,每組之間間距較明顯,有明顯分組跡象。ruby

2.數據源

說完了UITableView的簡介,下面來講說他它是如何展現數據的。性能優化

  1. UITableView要展現數據必須設置數據源,沒有數據源(DataSource)它就是一個空殼。
  2. UITableView會調用數據源方法來查詢一共有多少行數據以及當前顯示什麼樣的數據。
  3. 凡是遵照 UITableViewDelegate的OC對象均可以作UITableView的數據源

UITableView和數據源的關係以下
markdown

 

數據源方法的調用過程app

  1. 調用以下方法,查詢一共有多少組數據

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
  2. 調用以下方法,查詢每一組一共有多少行數據

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
  3. 調用以下方法,查詢每一行顯示什麼樣的內容

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

UITableView還有一些其餘的數據源方法以下

/**
 *  返回組頭標題
 */
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
/**
 *  返回尾標題
 */
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;

···

3.UITableViewCell的複用機制

3.1. 返回UITableViewCell的數據源方法的調用

最簡單的返回UITableViewCell的方法以下

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[UITableViewCell alloc] init];
    cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
    
    return cell;
}

可是實際使用過程當中這樣是很是耗費性能的,由於當用戶滑動UITableView的時候,上面方法會瘋狂的調用,瘋狂的建立UITableViewCell。

蘋果對這種狀況作了一些性能優化,UITableViewCell在每次建立的時候只會建立當前UI頁面上可見的Cell。當Cell滑動到屏幕外面,當前Cell會被放入到緩存池中,而且能夠給Cell設置一個複用標識,當下次使用Cell的時候能夠先到緩存池中查找,若是有對應複用標識的Cell就直接拿出來使用,並從新給內容賦值。

因此根據蘋果複用Cell的思路咱們在調用返回cell的方法思路應該以下:

  • 1.先從緩存池中查找看有沒有能夠複用的cell
  • 2.若是有就直接用,若是沒有在根據 複用標識 建立
  • 3.建立完成以後對原來數據進行覆蓋(防止複用的cell展現異常數據)

因此上面方法從提升性能角度考慮,應該從新寫爲下面這樣:

3.2. UITableView性能優化--Cell複用方式1

/**
 *  何時調用:每當有一個cell進入視野範圍的時候調用
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 0.建立cell複用標識
    static NSString *reuseIdentifier = @"cell";
    
    // 1.根據複用標識在複用池中進行查找
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    // 2.判斷若是複用池cell爲nil就根據複用標識本身建立
    if (cell == nil) {
        
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    }
    
    // 3.拿到cell進行數據覆蓋
    cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
    
    return cell;
}

3.2. UITableView性能優化--Cell複用方式2

咱們能夠手動給tableview註冊對應標識的cell,保證從緩存池中能加載到對應標識的cell。

經過代碼註冊

// 註冊cell
static NSString *reuseIdentifier = @"cell";
[tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:reuseIdentifier];

經過Xib註冊

// 註冊cell
static NSString *reuseIdentifier = @"cell"; // 標識能夠在Xib中建立
    [tableview registerNib:[UINib nibWithNibName:@"對應的Xib名稱" bundle:nil] forCellReuseIdentifier:reuseIdentifier];

在數據源方法中返回cell

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 1.根據複用標識在複用池中進行查找
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    
    // 2.拿到cell進行數據覆蓋
    cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
    
    return cell;
}

3.3 UITableView性能優化--Cell複用方式3

第三種方式是經過UITableViewController在StoryBoard中建立,見下面:5.UITableViewController

4.UITableView的代理方法

有了數據源方法,tableview就能夠正常展現數據。有了對應的代理方法就能夠正常監聽tableview的事件操做。

下面列舉一些經常使用代理方法:

/**
 返回行高,可根據不一樣行返回不一樣高
 
 @param tableView tableview
 @param indexPath 位置
 @return 行高
 */
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

/**
 返回估計行高,此方法不進行真實計算,課改變Cell計算高度方法的調用順序,
 
 @param tableView tableview
 @param indexPath 位置
 @return 行高
 */
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;


/**
 cell的點擊事件處理
 
 @param tableView tableview
 @param indexPath 位置
 */
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

/**
 cell將要被選中 -- 先需取消選中某個cell才能正常選中新的cell
 */
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
/**
 cell將要被取消選中
 */
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath 

···

5.UITableViewController

UITableViewController繼承自UIViewController。能夠方便建立有tableview的控制器

  • UITableViewController默認擁有tableview。在UITableViewController中 self.tableView 就是 self.view
  • UITableViewController默認繼承 UITableViewDelegate和UITableViewDataSource,全部能夠直接實現對應的數據源方法和代理方法便可。
  • 若是在StoryBoard中錯誤將UIViewController當作UITableViewController使用會報:加載不到UITableview的錯誤

     

  • 在StoryBoard中建立UITableViewController並加載cell步驟以下:

    1. 拖一個UITableViewController出來
    2. 設置initial view controller(程序第一個加載項)
    3. 修改對應的類型爲本身建立的VC(若是有)
    4. 設置Dynamic Prototypes動態類型的內容,下面數量至少爲1

    5. 設置cell的複用標識identfier

    6. 在代碼中直接加載對應cell便可(無需判空/建立)

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    // 1.會默認去緩存池中進行查找,若是沒有自動去StoryBaord中找
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    
    // 2.拿到cell進行數據覆蓋
    cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
    
    return cell;
    }

    經過StoryBoard建立Cell更加方便

小結

  • UITableView是iOS開發中經常使用的UI控件
  • UITableView須要實現數據源方法,來肯定本身展現什麼內容,沒有數據源的UITableview只是一個空架子
  • UITableView能夠經過複用UITableViewCell來實現性能優化
  • Cell複用的方式有三種(如上)
  • UITableViewController來實現帶有tableview的頁面更方便
相關文章
相關標籤/搜索