做爲iOS開發,UITableView多是平時咱們打交道最多的UI控件之一,其重要性不言而喻。ios
關於TableView,我想最核心的就是UITableViewCell的重用機制了。git
簡單來講呢就是當TableView滾動時,會調tableView:cellForRowAtIndexPath:這個方法,TableView只會建立屏幕內或者只比屏幕多一點點的cell,當滾動須要展示新的cell的時候,TableView首先會把已經移出屏幕外的cell放入到緩存池中去,而後再從緩存池中取出新的cell用來展現,當緩存池中沒有的時候,則會建立新的cell。可是cell可能不只僅是一種,咱們怎麼來辨別咱們須要的cell呢?蘋果公司已經爲咱們作好了一切,咱們只須要簡單地設置一個identifier便可,TableView即可自動根據identifier從緩存池中去出相應cell出來複用。這樣就極大的節省了內存的開銷。 github
知道cell的複用原理後,咱們再來看看TableView的回調方法。咱們知道,TableView繼承自UIScrollView,必須先肯定它的contentSize和每一個cell的位置,這樣才能正確的放置每一個cell。因此在建立或者複用cell以前,tableView會調用tableView:heightForRowAtIndexPath:來肯定contentSize和每一個cell的高度,以後再調用tableView:cellForRowAtIndexPath:顯示相應的cell。然而此舉對於那些成百上千不定高的cell,計算高度會至關消耗性能。緩存
因此首先咱們圍繞cell來看看TableView如何進行優化。多線程
1.cell複用異步
這個很簡單,只要註冊一下,便會自動複用ide
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *Identifier = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } return cell; }
這裏說一句,有不少人會在這裏給cell進行賦值操做,綁定數據,可是最近看了一篇文章https://medium.com/ios-os-x-development/perfect-smooth-scrolling-in-uitableviews-fd609d5275a5#.373u9fh4p,裏面說到不要在這個方法中進行數據綁定,由於TableView會爲每一個cell調用一次這個方法,它應該快速執行,咱們應該快速的返回cell重用實例。咱們能夠在tableView:willDisplayCell:forRowAtIndexPath:這個方法中進行數據綁定。性能
2.cell的高度計算優化
這邊咱們分爲兩種cell,一種是定高的cell,另一種是動態高度的cellui
a.定高的cell,應該採用以下方式:
self.tableView.rowHeight = 88;
這個方法指定了全部cell高度都是88的tableview,rowHeight默認的值是44,因此一個空的TableView會顯示成這個樣子。對於定高cell,直接採用上面方式給定高度,不須要實現tableView:heightForRowAtIndexPath:以節省沒必要要的計算和開銷。
b.動態高度的cell
咱們須要實現它的代理,來給出高度:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // return xxx }
這個方法給出後,上面的rowHeight的設置將會變成無效。在這個方法中,咱們須要提升cell高度的計算效率,來節省時間。
須要說明的是自從iOS8以後有了self-sizing cell的概念,cell能夠本身算出高度,但目前市面上的公司最低支持iOS8,能用上這個方法可能還有很久。
除了提升cell高度的計算效率以外,對於已經計算出的高度,咱們須要進行緩存,對於已經計算過的高度,沒有必要進行計算第二次。
此外,具體對於如何優化cell高度計算,什麼時候緩存cell高度,這篇博客給出了很是好的說明,強烈推薦有興趣的深讀一下。http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/
3.渲染
爲了保證TableView的流暢,當快速滑動的時候,cell必須被快速的渲染出來。因此cell渲染的速度必須快。如何提升cell的渲染速度呢?
a.當有圖像時,預渲染圖像,在bitmap context先將其畫一遍,導出成UIImage對象,而後再繪製到屏幕,這會大大提升渲染速度。具體作法能夠參考:《利用預渲染加速顯示iOS圖像》
b.渲染最好時的操做之一就是混合(blending)了,因此咱們不要使用透明背景,將cell的opaque值設爲Yes,背景色不要使用clearColor,儘可能不要使用陰影漸變等
c.因爲混合操做是使用GPU來執行,咱們能夠用CPU來渲染,這樣混合操做就再也不執行。能夠在UIView的drawRect方法中自定義繪製,具體可參考:http://southpeak.github.io/blog/2015/12/20/perfect-smooth-scrolling-in-uitableviews/
4.減小視圖的數目
咱們在cell上添加系統控件的時候,實際上系統都會調用底層的接口進行繪製,大量添加控件時,會消耗很大的資源而且也會影響渲染的性能。當使用默認的UITableViewCell而且在它的ContentView上面添加控件時會至關消耗性能。因此目前最佳的方法仍是繼承UITableViewCell,並重寫drawRect方法。
5.減小多餘的繪製工做
在實現drawRect方法的時候,它的參數rect就是咱們須要繪製的區域,在rect範圍以外的區域咱們不須要進行繪製,不然會消耗至關大的資源
6.不要給cell動態添加subView
在初始化cell的時候就添加好,而後根據須要來設置hide屬性顯示和隱藏
7.異步化UI,不要阻塞主線程
咱們時常會看到這樣一個現象,就是加載時整個頁面卡住不動,怎麼點都沒用,彷彿死機了通常。緣由是主線程被阻塞了。因此對於網路數據的請求或者圖片的加載,咱們能夠開啓多線程,異步話操做
8.滑動時按需加載對應的內容
//按需加載 - 若是目標行與當前行相差超過指定行數,只在目標滾動範圍的先後指定3行加載。 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{ NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)]; NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject]; NSInteger skipCount = 8; if (labs(cip.row-ip.row)>skipCount) { NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, self.width, self.height)]; NSMutableArray *arr = [NSMutableArray arrayWithArray:temp]; if (velocity.y<0) { NSIndexPath *indexPath = [temp lastObject]; if (indexPath.row+33) { [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-3 inSection:0]]; [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-2 inSection:0]]; [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:0]]; } } [needLoadArr addObjectsFromArray:arr]; } }
記得在tableView:cellForRowAtIndexPath:方法中加入判斷:
if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) { [cell clear]; return; }
滑動很快時,只加載目標範圍內的cell,這樣按需加載(配合SDWebImage),極大提升流暢度。
最後,對於TableView的優化還有不少方面沒有說起,但願你們多多交流~
參考文章
http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/
http://southpeak.github.io/blog/2015/12/20/perfect-smooth-scrolling-in-uitableviews/