UITableView-FDTemplateLayoutCell 源碼分析

UITableView-FDTemplateLayoutCell 源碼分析

以下簡稱 UITableView-FDTemplateLayoutCellFDT计济。

FDT

FDT 的作用在我看來就是可以緩存 Cell 高度。如果你還不知道為什么需要緩存 Cell 高度的話胁住,可以先看下這篇文章 UITableViewCell 自動高度五芝,了解下 iOS8 開始如何實現(xiàn) Cell 的自動算高痘儡,并且為什么需要緩存已經計算過的 Cell 的高度。

那么只是實現(xiàn)緩存高度的話枢步,為什么還需要分析 FDT 的源碼呢沉删?因為 FDT 源碼寫得很好,要不那么多 star 呢醉途、群眾的眼睛是雪亮的矾瑰。就這一點就足以讓我們分析下 FDT 是如何實現(xiàn)代碼的。

明確目標

通過 UITableViewCell 自動高度隘擎,我們知道了要實現(xiàn)高度緩存我們需要做的工作如下:

  1. 決定合適的 Cache Key
  2. 選取合適的 Cache Storage
  3. 在 Delete/Insert 發(fā)生時調整緩存數據

于是我們就可以以這幾個為目標分析下它們在 FDT 中的實現(xiàn)殴穴。

Cache Key

UITableViewCell 自動高度 中我們已經知道了,indexPath 是可以作為 Cache Key 的货葬,那是我們但從 Cell 角度考慮后的結論采幌。但是 FDT 是很用心的,它除了提供了 indexPath 作為 Cache Key 的方式震桶,還提供了另外一個 API:

- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier 
                               cacheByKey:(id<NSCopying>)key 
                            configuration:(void (^)(id cell))configuration;

這個 API 可以讓我自由的決定 Cache Key 的來源休傍,并且 FDT 還很貼心的告訴我們,可以使用 unique entity identifier蹲姐。

我們知道數據庫中的內容可以通過 ORM 變成 relational entities磨取,比如你有一個 Student 表,里面每一行都是一個學生的信息柴墩,于是 ORM 之后每行就是一個 entity忙厌,而 primary key(通常就是 autoincrement-id) 就可以作為 Cache Key。

這是 FDT 的相關例子:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    Entity *entity = self.entities[indexPath.row];
    return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByKey:entity.uid configuration:^(id cell) {
        // configurations
    }];
}

Cache Storage

UITableViewCell 自動高度 中我們已經分析了一個可以作為 Storage 的候選江咳,最后得出 objc_setAssociatedObjectNSMutableArray 性能要大幅度優(yōu)于 NSCache慰毅。那么我們可以看看 FDT 的實現(xiàn)是不是符合我們的期望。

通過閱讀源碼扎阶,我們會發(fā)現(xiàn)在 FDT 中同時使用了 objc_setAssociatedObjectNSMutableArray汹胃。

objc_setAssociatedObject

先說說使用 objc_setAssociatedObject 的地方,分別是:

  1. fd_indexPathHeightCache
  2. fd_keyedHeightCache
  3. ...

我們就看兩個典型的东臀,它們有下面的特性:

  1. lazy initialized
  2. OBJC_ASSOCIATION_RETAIN_NONATOMIC 到了 UITableView 實例上

這么做的好處呢着饥?很明顯啊:

  1. lazy initialized惰赋,就是在用到相關的緩存策略時才會初始化其 Cache Storage
  2. 將 Cache 的釋放托管給了 UITableView 實例的生命周期宰掉,不用管釋放內存的事情了

也是由于第 2 點優(yōu)勢(或者說需求)吧呵哨,那些地方才用了 objc_setAssociatedObject。所以說具體用什么是酌情而定的轨奄,沒有銀彈孟害。

NSMutableArray

那么哪里用了 NSMutableArray 來作為 Cache Storage 呢?分別是:

  1. FDKeyedHeightCache
  2. FDIndexPathHeightCache
  3. ...

還是就看兩個典型挪拟。我們注意到挨务,不論是 KeyedHeightCacheIndexPathHeightCache 都將緩存數據放到了 NSMutableArray。為什么這里就不用 objc_setAssociatedObject 了呢玉组?

回憶我們在 UITableViewCell 自動高度 中分析的谎柄,如果使用了 indexPath 作為 Cache Key,那么在發(fā)生了 Delete/Inert 之后惯雳,緩存中的 Cache Key 就『不準』了朝巫,需要進行相應的變動,那么采用了 NSMutableArray 它能為我們自動的變動石景。

另外在采用 IndexPathHeightCache 時劈猿,F(xiàn)DT 的緩存是一個二維的數組,頭一維定位到 Section潮孽,后一維定位到 Row糙臼,這樣就可以同時管到 SectionsRows 的數據變動。為什么這里要提一下呢恩商,因為一般說到使用 indexPath 做 Cache Key,那么首先想到的就是:

cacheKey = fmt("%d-%d", indexPath.section, indexPath.row)

但是這樣的 Key 生成方式不能適應我們這里需要同時靈活處理 SectionsRows 變動的情況必逆。

在 Delete/Insert 發(fā)生時調整緩存數據

這一步其實是 FDT 為我們做得最重要的一步怠堪,因為自己實現(xiàn)緩存存儲還是相對簡單的,但是在一有 Section/Rows 發(fā)生 Delete/Insert 就及時更改緩存數據是有點麻煩的名眉。

如果讓我去實現(xiàn)在 Section/Row 發(fā)生 Delete/Insert 就及時更改緩存數據粟矿,我會這么做(請叫我反面教材??):

  1. 繼承 UITableView 產生 MCUITableView
  2. MCUITableView 中重寫涉及 Section/Row 的 Delete/Insert 的方法以調整緩存數據
  3. 同時 MCUITableView 會向外暴露一個屬性 mcDelegate,這個屬性是 UITableViewDelegate 類型损拢,使用者需要設置這個屬性陌粹。在我的重寫方法中發(fā)現(xiàn)使用者實現(xiàn)了 UITableViewDelegate 中的同名方法時會調用它們,這樣使得使用起來和 UITableView 一樣

既然是反面教材福压,那么這個方案的缺點是:

  1. 實現(xiàn)起來不靈活掏秩,多處重寫
  2. 使用起來不靈活,需要更改很多已有的代碼荆姆,原來繼承 UITableView 的現(xiàn)在需要繼承 MCUITableView

FDT 使用 Category 的方式提供了便捷的 API蒙幻,肯定不能在這里掉鏈子。重寫肯定是繞不開的胆筒,F(xiàn)DT 采用了更加靈活的方式來完成重寫 method_exchangeImplementations邮破,代碼在 L156,通過將 UITableView 的相關方法使用 method_exchangeImplementations 和 FDT 自己的方法調換一下,真是很巧妙的抒和。

IndexPathHeightCache or KeyedHeightCache

IndexPathHeightCacheKeyedHeightCache 在實現(xiàn)和使用上還有些區(qū)別:

  1. IndexPathHeightCache 在實現(xiàn)上需要在 Section/Row 發(fā)送變動時調整緩存矫渔,而 KeyedHeightCache 不需要
  2. IndexPathHeightCache 使用了 indexPath 作為 Key,而 KeyedHeightCache 需要你自己確保 Key 是唯一的
  3. 如果你自己可以確保 Key 是唯一的摧莽,那么 KeyedHeightCache 肯定是會稍微快點的(因為不需要調整緩存)

estimatedRowHeight

estimatedRowHeight 的好處我們在 UITableViewCell 自動高度 中已經說過了庙洼。

但是,你用了 FDT 之后范嘱,就不要設置這個值了送膳,F(xiàn)DT 提倡的就是讓 UITableView 一次計算所有的 Cell's height,原文見 cell-height-calculation

估算高度設計初衷是好的丑蛤,讓加載速度更快叠聋,那憑啥要去侵害滑動的流暢性呢,用戶可能對進入頁面時多零點幾秒加載時間感覺不大受裹,但是滑動時實時計算高度帶來的卡頓是明顯能體驗到的碌补,個人覺得還不如一開始都算好了呢(iOS8更過分,即使都算好了也會邊劃邊計算)

如果你非要用的話棉饶,反正我在 FDT 提供了 Demo 中設置了結果是這樣:

抖起來

如果非要用的話三思吧??

疑惑

目前發(fā)現(xiàn)的 FDT 源碼中這一處關于 methodSignatureForSelector 讓我很困惑調用的作用是什么厦章,見 L122,我注釋掉也沒發(fā)現(xiàn)什么問題 ??照藻,一定是我打開的方式不對袜啃,總之希望有明白可以告訴我吧,不甚感激??幸缕。

最后群发,happy coding!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市发乔,隨后出現(xiàn)的幾起案子熟妓,更是在濱河造成了極大的恐慌,老刑警劉巖栏尚,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件起愈,死亡現(xiàn)場離奇詭異,居然都是意外死亡译仗,警方通過查閱死者的電腦和手機抬虽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纵菌,“玉大人斥赋,你說我怎么就攤上這事〔” “怎么了疤剑?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵滑绒,是天一觀的道長。 經常有香客問我隘膘,道長疑故,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任弯菊,我火速辦了婚禮纵势,結果婚禮上,老公的妹妹穿的比我還像新娘管钳。我一直安慰自己钦铁,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布才漆。 她就那樣靜靜地躺著牛曹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪醇滥。 梳的紋絲不亂的頭發(fā)上黎比,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音鸳玩,去河邊找鬼阅虫。 笑死,一個胖子當著我的面吹牛不跟,可吹牛的內容都是我干的颓帝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼窝革,長吁一口氣:“原來是場噩夢啊……” “哼购城!你這毒婦竟也來了?” 一聲冷哼從身側響起聊闯,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎米诉,沒想到半個月后菱蔬,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡史侣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年拴泌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惊橱。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚪腐,死狀恐怖,靈堂內的尸體忽然破棺而出税朴,到底是詐尸還是另有隱情回季,我是刑警寧澤家制,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站泡一,受9級特大地震影響颤殴,放射性物質發(fā)生泄漏。R本人自食惡果不足惜鼻忠,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一涵但、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帖蔓,春花似錦矮瘟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钝吮,卻和暖如春埋涧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奇瘦。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工棘催, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耳标。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓醇坝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親次坡。 傳聞我的和親對象是個殘疾皇子呼猪,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容