UITableViewCell的重用

當(dāng)我們在談cell重用的時候我們在談什么?

好的程序員都是"懶"的.他們在實(shí)現(xiàn)需求的時候,比如說:盡可能的少敲代碼,盡可能的在設(shè)計的時候,考慮以后的需求變動,最后還有就是盡可能的避免出bug...盡管,事實(shí)上,bug總會有的.要想少出bug,對于iOS開發(fā)來說,我覺得還是多了解一些稍微底層的運(yùn)作機(jī)制.比如說當(dāng)你從cell的復(fù)用隊列,出隊一個cell的時候,你知道這個方法做了什么.

cell的重用

  1. 當(dāng)我們需要使用兩種具有相似布局的cell的時候,我們一般會想到"重用"代碼.這個時候,這個時候我們有一些方式來復(fù)用自己的代碼.比如說:搞一個baseCell抽取公用的部分,然后繼承或者添加分類.但是做這些的目的都是少寫代碼!不會減少最終最后創(chuàng)建對象. 最終,我們只會較少應(yīng)用的安裝包的磁盤容量.而不會減少應(yīng)用運(yùn)行時所占的內(nèi)存.
  2. 系統(tǒng)也給我們提供了一種復(fù)用的方案,但是這里"復(fù)用"的概念,和上面的代碼復(fù)用是完全不同的兩個概念.這里的復(fù)用是內(nèi)存中對象的復(fù)用. 可以這么理解.對于應(yīng)用來說,誰占用的內(nèi)存少,誰的"生命力"就頑強(qiáng).無論是操作系統(tǒng)還是用戶都不太喜歡,大內(nèi)存應(yīng)用.
  3. 回到主題!我們在談的cell復(fù)用是指什么,我想更多的是避免對象重復(fù)創(chuàng)建.其所指的是內(nèi)存復(fù)用. 但是某些時候,我們對內(nèi)存的復(fù)用要適可而止.比如說:你不應(yīng)該在cell的動態(tài)的創(chuàng)建太多的布局,然后復(fù)用的時候,像cell內(nèi)傳入不同的數(shù)據(jù)源,來動態(tài)創(chuàng)建和布局cell內(nèi)部的子控件. 相反,應(yīng)該再自定義一個類型的cell,并向tableView注冊一個identifier.只需要創(chuàng)建一個復(fù)用對象,你可以讓CPU少做那么多事情.

談一下UITableViewCell的復(fù)用原理

  • 等高cell
  • 不等高cell
    一般情況下,除了簡單的展示基本的描述性標(biāo)題內(nèi)容,(如iPhone手機(jī)中的設(shè)置應(yīng)用.),我們使用tableView都是自定義不等高的tableViewCell.我們也可以自定義不等高cell. 相對來說自定義不等高cell,布局和計算高度是很消耗性能的. 這是因?yàn)橄到y(tǒng)在顯示不等高cell的過程是這樣的.
  1. 第一步調(diào)用數(shù)據(jù)源方法(- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;)得到一個cell對象.
  2. 第二步調(diào)用代理方法(- (CGFloat)tableView:(UITableView )tableView heightForRowAtIndexPath:(NSIndexPath )indexPath;)獲取cell的高度.
    雖然核心的方法就這兩個,但是每個cell都是這么調(diào)用的話,再加上如果計算cell高度的方法過于
    臃腫
    那么性能堪憂...如果不得不這么做的話,要注意性能優(yōu)化.這個以后再介紹. 如果僅僅是等高cell的話,只需要在創(chuàng)建tableView的時候,統(tǒng)一設(shè)置一下cell的高度就OK了.
/**統(tǒng)一設(shè)置tableViewCell的高度.但是如果實(shí)現(xiàn)了計算cell高度的代理方法仍然會以tableView代理方法的覆蓋值為準(zhǔn)
*/
UITableView* tableView = [[UITableView alloc]initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
//通過tableView的rowHeight屬性,統(tǒng)一設(shè)置cell高度.
tableView.rowHeight = 40.0;

/**除此之外,sectionFooterHeight,sectionHeaderHeight都可以這樣統(tǒng)一設(shè)置高度
*/
    self.tableView.sectionHeaderHeight = 10.0f;
    self.tableView.sectionFooterHeight = 10.0f;

在談tableView是如何復(fù)用tableViewCell的原理之前,先看一下如何重用一個UITableViewCell?

  • 第一種方式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
    
    return cell;
}

這是iOS 6.0之后的方法,這種方法需要提前使用- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString )identifier NS_AVAILABLE_IOS(6_0); 方法注冊,否則在使用第一種方式從內(nèi)存復(fù)用池中取的時候,會崩!使用這種方式,只需要注冊cell,就可以了. 在使用的過程中,直接從復(fù)用隊列直接出隊特定identifier*類型的cell就可以了.不需要檢查是否為空,當(dāng)你調(diào)用這個方法的時,這些操作,tableView的復(fù)用機(jī)制已經(jīng)為你做好了.

  • 第二種重用的方式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identify];
    
if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identify];
    }

    return cell;
}

使用第二種方法的時候,要檢查cell是否為空,當(dāng)cell為空的時候,需要你手動調(diào)用cell的指定初始化方法來獲取一個cell,并傳入identifier,這個方法會自動向tableView注冊一個特定類型的cell.事實(shí)上,方法一也是這么做的.我們在自定義cell的時候,覆蓋系統(tǒng)指定初始化方法.復(fù)用的該方法被系統(tǒng)調(diào)用并自動注冊一個identifier.

這是cell能被復(fù)用的重要原因
Designated initializer. If the cell can be reused, you must pass in a reuse identifier. You should use the same reuse identifier for all cells of the same form.

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier NS_AVAILABLE_IOS(3_0) NS_DESIGNATED_INITIALIZER;

UITableViewCell復(fù)用介紹

實(shí)在不敢,加上"原理"兩個字,介紹一下我的理解.每個tableView在創(chuàng)建的時候都會,有一個復(fù)用池(底層就是一塊內(nèi)存,也即是放復(fù)用cell的地方),這個復(fù)用池在剛開始的時候是空的.即沒有復(fù)用cell在里面.當(dāng)復(fù)用池里面有許多個cell的時候,它們這些復(fù)用cell是被一個隊列管理的.蘋果肯定對這個隊列做了一些優(yōu)化機(jī)制,比如說可以讓你很快的根據(jù)一個"identifier"從復(fù)用池中快速出隊一個特定的復(fù)用cell.

  1. 復(fù)用池中的reuse cell 是什么時候被添加的.
  • 當(dāng)我們使用第一種方式復(fù)用的時候,注冊時向復(fù)用池添加reuse cell .
//不僅僅cell可以復(fù)用,sectionHeaderView, sectionFooterView也可以.甚至通過XIB創(chuàng)建的對象都可以
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier
//復(fù)用sectionHeaderFooterView也需要向tableView注冊
- (void)registerClass:(nullable Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
  • 當(dāng)我們使用第二種方式復(fù)用cell的時候,創(chuàng)建cell被第一次創(chuàng)建的時候根據(jù)identifier自動向tableView注冊.
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier NS_AVAILABLE_IOS(3_0) NS_DESIGNATED_INITIALIZER;

總結(jié):復(fù)用就是從復(fù)用池(就是一塊內(nèi)存中有許多用過的已注冊cell),中根據(jù)identifier取出一個特定的cell.

  1. 取出的cell有沒有被初始化.
  • tableView利用它的復(fù)用機(jī)制,避免了我們重復(fù)創(chuàng)建cell.試想如果沒有復(fù)用機(jī)制,我們要么需要不斷的創(chuàng)建cell,不銷毀. 要么就是不斷的創(chuàng)建,不斷的銷毀.tableView復(fù)用則是讓我們,需要cell的時候,從復(fù)用池中去取,你只需要告訴它你需要什么類型的cell就好了.這時候會出現(xiàn)兩個情況,第一種是沒取到.然后系統(tǒng)根據(jù)它的復(fù)用機(jī)制(第二種使用方式),自動的創(chuàng)建了一個cell并注冊了,添加到復(fù)用池.這時候,下次再從復(fù)用池去取這個類型的cell時候,復(fù)用池因?yàn)橐呀?jīng)存在,所以直接返回上次使用的cell.注意此時返回的是上次使用后完整的狀態(tài),也就是說已經(jīng)初始化了.
  • 當(dāng)我們需要一個"干凈的"的cell時候,我們需要自己手動去清除這個剛剛從復(fù)用池中取到的cell,尤其是我們在自定義cell里面做了太多自定義布局子控件的操作,這個時候,你需要移除所有的子控件.或者在自定義cell內(nèi)部做一些操作.
  • 每次當(dāng)我們?nèi)〉脧?fù)用cell的時候,cell會調(diào)用其內(nèi)部的一個方法
//需要調(diào)用其父方法,每次返回復(fù)用cell都會調(diào)用這個方法,我們可以在這個方法來清除不需要的子控件.
- (void)prepareForReuse NS_REQUIRES_SUPER;                                                        // if the cell is reusable (has a reuse identifier), this is called just before the cell is returned from the table view method dequeueReusableCellWithIdentifier:.  If you override, you MUST call super.

最后,幾點(diǎn)建議:適量組織代碼,避免在cell內(nèi)部反復(fù)操作子控件,應(yīng)該重新注冊一個特定類型的cell.每次從復(fù)用池中取出cell的時候,注意初始化(清除干凈上次的殘留物).不要濫用復(fù)用機(jī)制,注冊太多種類的cell

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诫尽,一起剝皮案震驚了整個濱河市绊序,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖占遥,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阶女,死亡現(xiàn)場離奇詭異,居然都是意外死亡拨与,警方通過查閱死者的電腦和手機(jī)稻据,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來买喧,“玉大人捻悯,你說我怎么就攤上這事「诤恚” “怎么了秋度?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钱床。 經(jīng)常有香客問我荚斯,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任事期,我火速辦了婚禮滥壕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘兽泣。我一直安慰自己绎橘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布唠倦。 她就那樣靜靜地躺著称鳞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稠鼻。 梳的紋絲不亂的頭發(fā)上冈止,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音候齿,去河邊找鬼熙暴。 笑死,一個胖子當(dāng)著我的面吹牛慌盯,可吹牛的內(nèi)容都是我干的周霉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼亚皂,長吁一口氣:“原來是場噩夢啊……” “哼俱箱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起孕讳,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤匠楚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后厂财,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芋簿,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年璃饱,在試婚紗的時候發(fā)現(xiàn)自己被綠了与斤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡荚恶,死狀恐怖撩穿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谒撼,我是刑警寧澤偿洁,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布人乓,位于F島的核電站,受9級特大地震影響队橙,放射性物質(zhì)發(fā)生泄漏丰刊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧移盆,春花似錦、人聲如沸伤为。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绞愚。三九已至叙甸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間爽醋,已是汗流浹背蚁署。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工便脊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚂四,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓哪痰,卻偏偏與公主長得像遂赠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子晌杰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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

  • UITableViewCell如果在tableView:cellForRowAtIndexPath:方法中跷睦,像其他...
    ForeverYoung21閱讀 5,993評論 3 16
  • TableView的重用機(jī)制,為了做到顯示和數(shù)據(jù)分離肋演,IOS tableView的實(shí)現(xiàn)并且不是為每個數(shù)據(jù)項創(chuàng)建一個...
    Levan_li閱讀 1,046評論 0 6
  • TableView的重用機(jī)制抑诸,為了做到顯示和數(shù)據(jù)分離,UITableView的實(shí)現(xiàn)并且不是為每個數(shù)據(jù)項創(chuàng)建一個Ce...
    AYuan_閱讀 638評論 0 2
  • TableView的重用機(jī)制爹殊,為了做到顯示和數(shù)據(jù)分離蜕乡,IOS tableView的實(shí)現(xiàn)并且不是為每個數(shù)據(jù)項創(chuàng)建一個...
    陌尚煙雨遙閱讀 5,477評論 4 6
  • 不由得在上班的途中打開手機(jī)微信看到大本營中分享的美好,不由得自己將精美的圖片及觸動著自己的那些語句截屏下來存儲梗夸,這...
    melody靜閱讀 206評論 0 0