本文的背景是,在實際項目中,咱們常常會遇到TabelView的cell高度須要根據內容自適應,但cell的高度不是應該在cell顯示前就已經設置好了嗎?如何才能根據內容自適應高度?爲此咱們一探TabelView運行的機制.git
下面給出本例的日誌
github
2016-01-28 10:15:18.981 SimpleImChat[1370:40265] viewDidLoad 2016-01-28 10:15:18.982 SimpleImChat[1370:40265] viewWillAppear 2016-01-28 10:15:18.993 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:15:18.994 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:15:18.997 SimpleImChat[1370:40265] viewWillLayoutSubviews 2016-01-28 10:15:18.999 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:15:18.999 SimpleImChat[1370:40265] viewDidLayoutSubviews 2016-01-28 10:15:19.000 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:15:19.001 SimpleImChat[1370:40265] -[ChatViewController tableView:cellForRowAtIndexPath:]:0 2016-01-28 10:15:19.056 SimpleImChat[1370:40265] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:15:19.058 SimpleImChat[1370:40265] viewWillLayoutSubviews 2016-01-28 10:15:19.059 SimpleImChat[1370:40265] viewDidLayoutSubviews 2016-01-28 10:15:19.064 SimpleImChat[1370:40265] viewDidAppear
能夠看到heightForRowAtIndexPath執行屢次,並且是先於cellForRowAtIndexPath執行的,那麼咱們是否是應該在heightForRowAtIndexPath裏面提早設置好cell的高度,而後cellForRowAtIndexPath執行的時候就已經能夠正確的顯示了呢?那麼如何才能正確獲取到cell的高度呢,cellForRowAtIndexPath執行前應該尚未數據的,有人會想到在heightForRowAtIndexPath裏面先給cell設數據,而後算好高度再取出來,對於IOS6及如下的版本,這倒是一種解決方案.但對於IOS7及以上的版本,這樣作將大大下降執行效率,由於heightForRowAtIndexPath會執行屢次,每次都去計算高度將很耗時.So,IOS7有了這樣的代理和屬性緩存
// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table. // If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there. - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0); @property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is 0, which means there is no estimate
這裏是IOS的UITableView.h文件中的聲明,這裏要注意裏面的註釋,根據註釋,咱們知道,若是設置了estimatedRowHeight或者實現了estimatedHeightForRowAtIndexPath代理,就不會頻繁調用heightForRowAtIndexPath了,然並卵,看LOGui
2016-01-28 10:26:30.175 SimpleImChat[1462:49281] viewDidLoad 2016-01-28 10:26:30.176 SimpleImChat[1462:49281] viewWillAppear 2016-01-28 10:26:30.189 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0 2016-01-28 10:26:30.190 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0 2016-01-28 10:26:30.194 SimpleImChat[1462:49281] viewWillLayoutSubviews 2016-01-28 10:26:30.195 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0 2016-01-28 10:26:30.196 SimpleImChat[1462:49281] viewDidLayoutSubviews 2016-01-28 10:26:30.198 SimpleImChat[1462:49281] -[ChatViewController tableView:estimatedHeightForRowAtIndexPath:]:0 2016-01-28 10:26:30.198 SimpleImChat[1462:49281] -[ChatViewController tableView:cellForRowAtIndexPath:]:0 2016-01-28 10:26:30.254 SimpleImChat[1462:49281] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:26:30.257 SimpleImChat[1462:49281] viewWillLayoutSubviews 2016-01-28 10:26:30.257 SimpleImChat[1462:49281] viewDidLayoutSubviews 2016-01-28 10:26:30.261 SimpleImChat[1462:49281] viewDidAppear
這裏咱們能夠清楚的看到,當實現了estimatedHeightForRowAtIndexPath代理後,是先執行cellForRowAtIndexPath後執行atom
heightForRowAtIndexPath,so,你能夠在cellForRowAtIndexPath中算好高度而後存下來,存到哪裏?存到View?存到model?其實均可以,但cell有重用,爲防止取錯cell(如何纔是正確的取法?讀者能夠思考一下),咱們將算好的高度存在model裏,這裏你能夠給model加一個屬性,或者動態綁定一個屬性,這樣在ViewController中,咱們是可以拿到全部數據的,而後根據indexPath是能夠正確取到當前cell對應的model的,這裏的model已經在cellForRowAtIndexPath執行的時候經過給view賦值算好了高度,而且存了下來.說了這麼多,可能有點凌亂了.spa
這裏附上代碼 git代碼
代理
須要說明一下若是在viewDidLoad中設置了estimatedRowHeight就不用實現對應的代理了,並且通常狀況這個預估高度都是定值,可是不能隨便設置,不能隨便設置,不能隨便設置,這裏大了小了都會有顯示的問題,讀者能夠嘗試一下,最好的就是設置一個平均值.日誌
2016-01-28 10:38:22.070 SimpleImChat[1524:58078] viewDidLoad 2016-01-28 10:38:22.071 SimpleImChat[1524:58078] viewWillAppear 2016-01-28 10:38:22.085 SimpleImChat[1524:58078] viewWillLayoutSubviews 2016-01-28 10:38:22.086 SimpleImChat[1524:58078] viewDidLayoutSubviews 2016-01-28 10:38:22.087 SimpleImChat[1524:58078] -[ChatViewController tableView:cellForRowAtIndexPath:]:0 2016-01-28 10:38:22.145 SimpleImChat[1524:58078] -[ChatViewController tableView:heightForRowAtIndexPath:]:0 2016-01-28 10:38:22.147 SimpleImChat[1524:58078] viewWillLayoutSubviews 2016-01-28 10:38:22.147 SimpleImChat[1524:58078] viewDidLayoutSubviews 2016-01-28 10:38:22.151 SimpleImChat[1524:58078] viewDidAppear
上面是設置了預估高度,而且不實現相關代理的LOG,因此,咱們看到這裏的執行是很高效的,即便你頻繁reload也影響不大,由於model裏已經緩存了對應的cell高度.code