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

如果問iOS中最重要的最常用的UI控件是什么,我覺得UITableView當(dāng)之無愧!似乎所有常規(guī)APP都使用到了UITableView。下面就講一講UITableView的常用知識(shí)和使用原理及性能優(yōu)化!

1.簡介

  • UITableView故名思議是一種表格控件,是iOS應(yīng)用中常用的表格控件。常見UITableView如圖:
Snip20170320_7.png
  • UITableView繼承于UIScrollview,因此它默認(rèn)支持垂直滾動(dòng)(只支持垂直滾動(dòng))

  • UITableView性能極佳,它可以出色的完成我們工作中的很多功能。

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

效果分別如圖:

Snip20170320_8.png

UITableViewStylePlain:一種平鋪的效果,并且分組組頭默認(rèn)有停靠效果;
UITableViewStyleGroup:一種組間分離的效果,每組之間間距較明顯,有明顯分組跡象。

2.數(shù)據(jù)源

說完了UITableView的簡介,下面來說說他它是如何展示數(shù)據(jù)的。

  1. UITableView要展示數(shù)據(jù)必須設(shè)置數(shù)據(jù)源,沒有數(shù)據(jù)源(DataSource)它就是一個(gè)空殼。
  2. UITableView會(huì)調(diào)用數(shù)據(jù)源方法來查詢一共有多少行數(shù)據(jù)以及當(dāng)前顯示什么樣的數(shù)據(jù)。
  3. 凡是遵守 UITableViewDelegate的OC對象都可以做UITableView的數(shù)據(jù)源

UITableView和數(shù)據(jù)源的關(guān)系如下

Snip20170320_9.png

數(shù)據(jù)源方法的調(diào)用過程

  1. 調(diào)用如下方法,查詢一共有多少組數(shù)據(jù)

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

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
    
  3. 調(diào)用如下方法,查詢每一行顯示什么樣的內(nèi)容

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

UITableView還有一些其他的數(shù)據(jù)源方法如下

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

···

3.UITableViewCell的復(fù)用機(jī)制

3.1. 返回UITableViewCell的數(shù)據(jù)源方法的調(diào)用

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

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

但是實(shí)際使用過程中這樣是非常耗費(fèi)性能的,因?yàn)楫?dāng)用戶滑動(dòng)UITableView的時(shí)候,上面方法會(huì)瘋狂的調(diào)用,瘋狂的創(chuàng)建UITableViewCell。

蘋果對這種情況做了一些性能優(yōu)化,UITableViewCell在每次創(chuàng)建的時(shí)候只會(huì)創(chuàng)建當(dāng)前UI頁面上可見的Cell。當(dāng)Cell滑動(dòng)到屏幕外面,當(dāng)前Cell會(huì)被放入到緩存池中,并且可以給Cell設(shè)置一個(gè)復(fù)用標(biāo)識(shí),當(dāng)下次使用Cell的時(shí)候可以先到緩存池中查找,如果有對應(yīng)復(fù)用標(biāo)識(shí)的Cell就直接拿出來使用,并重新給內(nèi)容賦值。

所以根據(jù)蘋果復(fù)用Cell的思路我們在調(diào)用返回cell的方法思路應(yīng)該如下:

  • 1.先從緩存池中查找看有沒有可以復(fù)用的cell
  • 2.如果有就直接用,如果沒有在根據(jù) 復(fù)用標(biāo)識(shí) 創(chuàng)建
  • 3.創(chuàng)建完成之后對原來數(shù)據(jù)進(jìn)行覆蓋(防止復(fù)用的cell展示異常數(shù)據(jù))

所以上面方法從提高性能角度考慮,應(yīng)該重新寫為下面這樣:

3.2. UITableView性能優(yōu)化--Cell復(fù)用方式1

/**
 *  什么時(shí)候調(diào)用:每當(dāng)有一個(gè)cell進(jìn)入視野范圍的時(shí)候調(diào)用
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 0.創(chuàng)建cell復(fù)用標(biāo)識(shí)
    static NSString *reuseIdentifier = @"cell";
    
    // 1.根據(jù)復(fù)用標(biāo)識(shí)在復(fù)用池中進(jìn)行查找
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    // 2.判斷如果復(fù)用池cell為nil就根據(jù)復(fù)用標(biāo)識(shí)自己創(chuàng)建
    if (cell == nil) {
        
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    }
    
    // 3.拿到cell進(jìn)行數(shù)據(jù)覆蓋
    cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
    
    return cell;
}

3.2. UITableView性能優(yōu)化--Cell復(fù)用方式2

我們可以手動(dòng)給tableview注冊對應(yīng)標(biāo)識(shí)的cell,保證從緩存池中能加載到對應(yīng)標(biāo)識(shí)的cell。

通過代碼注冊

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

通過Xib注冊

// 注冊cell
static NSString *reuseIdentifier = @"cell"; // 標(biāo)識(shí)可以在Xib中創(chuàng)建
    [tableview registerNib:[UINib nibWithNibName:@"對應(yīng)的Xib名稱" bundle:nil] forCellReuseIdentifier:reuseIdentifier];

在數(shù)據(jù)源方法中返回cell

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

3.3 UITableView性能優(yōu)化--Cell復(fù)用方式3

第三種方式是通過UITableViewController在StoryBoard中創(chuàng)建,見下面:5.UITableViewController

4.UITableView的代理方法

有了數(shù)據(jù)源方法,tableview就可以正常展示數(shù)據(jù)。有了對應(yīng)的代理方法就可以正常監(jiān)聽tableview的事件操作。

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

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

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


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

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

···

5.UITableViewController

UITableViewController繼承自UIViewController。可以方便創(chuàng)建有tableview的控制器

  • UITableViewController默認(rèn)擁有tableview。在UITableViewController中 self.tableView 就是 self.view

  • UITableViewController默認(rèn)繼承 UITableViewDelegate和UITableViewDataSource,所有可以直接實(shí)現(xiàn)對應(yīng)的數(shù)據(jù)源方法和代理方法即可。

  • 如果在StoryBoard中錯(cuò)誤將UIViewController當(dāng)做UITableViewController使用會(huì)報(bào):加載不到UITableview的錯(cuò)誤


    Snip20170321_10.png
  • 在StoryBoard中創(chuàng)建UITableViewController并加載cell步驟如下:

    1. 拖一個(gè)UITableViewController出來

    2. 設(shè)置initial view controller(程序第一個(gè)加載項(xiàng))

    3. 修改對應(yīng)的類型為自己創(chuàng)建的VC(如果有)

    4. 設(shè)置Dynamic Prototypes動(dòng)態(tài)類型的內(nèi)容,下面數(shù)量至少為1


      Snip20170321_11.png
    5. 設(shè)置cell的復(fù)用標(biāo)識(shí)identfier
      Snip20170321_12.png
    6. 在代碼中直接加載對應(yīng)cell即可(無需判空/創(chuàng)建)

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

{
// 1.會(huì)默認(rèn)去緩存池中進(jìn)行查找,如果沒有自動(dòng)去StoryBaord中找
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

// 2.拿到cell進(jìn)行數(shù)據(jù)覆蓋
cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];

return cell;

}

```

**通過StoryBoard創(chuàng)建Cell更加方便**

小結(jié)

  • UITableView是iOS開發(fā)中常用的UI控件
  • UITableView需要實(shí)現(xiàn)數(shù)據(jù)源方法,來確定自己展示什么內(nèi)容,沒有數(shù)據(jù)源的UITableview只是一個(gè)空架子
  • UITableView可以通過復(fù)用UITableViewCell來實(shí)現(xiàn)性能優(yōu)化
  • Cell復(fù)用的方式有三種(如上)
  • UITableViewController來實(shí)現(xiàn)帶有tableview的頁面更方便
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,238評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,339評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,713評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評(píng)論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,893評(píng)論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,448評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,201評(píng)論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,397評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,631評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評(píng)論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,128評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,347評(píng)論 2 377

推薦閱讀更多精彩內(nèi)容