最近在微博上看到一個很好的開源項目,是關於如何優化UITableView的,加上正好最近也在優化項目中的相似朋友圈功能這塊,思考了不少關於UITableView的優化技巧,因此決定詳細的整理下對優化UITableView的理解,須要的朋友們能夠參考借鑑。面試
1、介紹緩存
iOS開發中,UITableView多是平時咱們打交道最多的UI控件之一,其重要性不言而喻。Android也是如此,Android中的ListView和UITableView是相同功能的一個控件,可是iOS的UITableView更爲強大一點,緣由就不說了,若是你學過Android就知道iOS中的UITableView使用起來是很是簡單的,這也是峯哥喜歡iOS賽過Android的緣由之一。今天研究的內容就是UITableView的優化。性能優化
開始以前,你能說出幾種UITableView的可優化項?cell複用(Android中常常稱爲ListView的重用,其實重用複用都是一個意思,因爲峯哥以前作過Android的緣由,有時候我常常說「重用」,後面萬一說「重用」你們知道是「複用」的意思就好了)!除了cell重用呢?多線程
2、UITableView的性能優化異步
一、cell複用ide
複用很簡單,這或許是全部iOS開發者最爲熟知的一個優化內容,以下代碼:佈局
-(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;
}性能
可是,這樣重用就完美了嗎?學習
咱們常常在注意cellForRowAtIndexPath:中爲每個cell綁定數據,實際上在調用cellForRowAtIndexPath:的時候cell尚未被顯示出來,爲了提升效率咱們應該把數據綁定的操做放在cell顯示出來後再執行,能夠在tableView:willDisplayCell:forRowAtIndexPath:(之後簡稱willDisplayCell)方法中綁定數據。優化
注意willDisplayCell在cell 在tableview展現以前就會調用,此時cell實例已經生成,因此不能更改cell的結構,只能是改動cell上的UI的一些屬性(例如label的內容等)。
二、cell高度的計算
這邊咱們分爲兩種cell,一種是定高的cell,另一種是動態高度的cell。
(1)定高的cell,應該採用以下方式:
self.tableView.rowHeight = 88;
這個方法指定了全部cell高度都是88的tableview,rowHeight默認的值是44,因此一個空的TableView會顯示成這個樣子。對於定高cell,直接採用上面方式給定高度,不須要實現tableView:heightForRowAtIndexPath:以節省沒必要要的計算和開銷。
(2)動態高度的cell
咱們須要實現它的代理,來給出高度:
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// return xxx
}
這個代理方法實現後,上面的rowHeight的設置將會變成無效。在這個方法中,咱們須要提升cell高度的計算效率,來節省時間。
自從iOS8以後有了self-sizing cell的概念,cell能夠本身算出高度,使用self-sizing cell須要知足如下三個條件:
(1)使用Autolayout進行UI佈局約束(要求cell.contentView的四條邊都與內部元素有約束關係)。
(2)指定TableView的estimatedRowHeight屬性的默認值。
(3)指定TableView的rowHeight屬性爲UITableViewAutomaticDimension。
(void)viewDidload {
self.myTableView.estimatedRowHeight = 44.0;
self.myTableView.rowHeight = UITableViewAutomaticDimension;
}
除了提升cell高度的計算效率以外,對於已經計算出的高度,咱們須要進行緩存,對於已經計算過的高度,沒有必要進行計算第二次。
做爲一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個個人iOS交流羣:519832104 無論你是小白仍是大牛歡迎入駐,分享經驗,討論技術,你們一塊兒交流學習成長!
另附上一份各好友收集的大廠面試題,須要iOS開發學習資料、面試真題,能夠添加iOS開發進階交流羣,進羣可自行下載!
三、渲染
爲了保證TableView的流暢,當快速滑動的時候,cell必須被快速的渲染出來。因此cell渲染的速度必須快。如何提升cell的渲染速度呢?
(1)當有圖像時,預渲染圖像,在bitmap context先將其畫一遍,導出成UIImage對象,而後再繪製到屏幕,這會大大提升渲染速度。具體內容能夠自行查找「利用預渲染加速顯示iOS圖像」相關資料。
(2)渲染最好時的操做之一就是混合(blending)了,因此咱們不要使用透明背景,將cell的opaque值設爲Yes,背景色不要使用clearColor,儘可能不要使用陰影漸變等
(3)因爲混合操做是使用GPU來執行,咱們能夠用CPU來渲染,這樣混合操做就再也不執行。能夠在UIView的drawRect方法中自定義繪製。
四、減小視圖的數目
咱們在cell上添加系統控件的時候,實際上系統都會調用底層的接口進行繪製,大量添加控件時,會消耗很大的資源而且也會影響渲染的性能。當使用默認的UITableViewCell而且在它的ContentView上面添加控件時會至關消耗性能。因此目前最佳的方法仍是繼承UITableViewCell,並重寫drawRect方法。
五、減小多餘的繪製操做
在實現drawRect方法的時候,它的參數rect就是咱們須要繪製的區域,在rect範圍以外的區域咱們不須要進行繪製,不然會消耗至關大的資源。
六、不要給cell動態添加subView
在初始化cell的時候就將全部須要展現的添加完畢,而後根據須要來設置hide屬性顯示和隱藏。
七、異步化UI,不要阻塞主線程
咱們時常會看到這樣一個現象,就是加載時整個頁面卡住不動,怎麼點都沒用,彷彿死機了通常。緣由是主線程被阻塞了。因此對於網路數據的請求或者圖片的加載,咱們能夠開啓多線程,將耗時操做放到子線程中進行,異步化操做。這個或許每一個iOS開發者都知道的知識,沒必要多講。
八、滑動時按需加載對應的內容
若是目標行與當前行相差超過指定行數,只在目標滾動範圍的先後指定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),極大提升流暢度。
總結
以上就是這篇文章的所有內容了,但願本文的內容對你們的學習或者工做能帶來必定的幫助,若是有疑問你們能夠留言交流。
點擊此處,當即與iOS大牛交流學習