iOS_項(xiàng)目優(yōu)化(tableview的優(yōu)化)

在項(xiàng)目開發(fā)中如果你沒用到過Tableview,那請你去火星好嗎。既然都用到了Tableview,那么如何優(yōu)化就是個(gè)問題了。網(wǎng)上查了一些博客結(jié)合自己的一些經(jīng)歷,講一下。

為什么會(huì)卡頓、掉幀、

先上圖
渲染圖.png

CPU:對象的創(chuàng)建和銷毀、對象屬性的調(diào)整、布局計(jì)算、文本的計(jì)算和排版、圖片的格式轉(zhuǎn)換和解碼、圖像的繪制
GPU:紋理的渲染
那這個(gè)卡頓掉幀是怎么發(fā)生的呢。
我們都知道iPhone的屏幕刷新是60,按照60FPS的刷幀率,每隔16ms就會(huì)有一次VSync信號(hào)。而產(chǎn)生卡頓掉幀就是因?yàn)镃PU或者GPU所花費(fèi)的時(shí)間過長,導(dǎo)致垂直信號(hào)來的時(shí)候,CPU計(jì)算或者GPU渲染未完成,從而掉幀。上一次的還沒能傳遞過來信號(hào),下一次的又開始了。所以,就造成了卡頓。
既然上面都說了事因?yàn)閏pu和cpu花費(fèi)的時(shí)間太長所引起的,那我們就從這兩個(gè)方面入手解決。

1.CPU優(yōu)化

1.固定高度的cell

self.tableView.rowHeight = 88;

2.動(dòng)態(tài)高度的cell
現(xiàn)在對于動(dòng)態(tài)高度這種情況,一般我們用系統(tǒng)的自動(dòng)適配就可以滿足。現(xiàn)在很少遇到還需要自己計(jì)算高度的情況。
不過還是要說在計(jì)算高度的時(shí)候,提前計(jì)算好cell的高度,緩存到數(shù)據(jù)源模型中。

 CGFloat contentW = [UIScreen mainScreen].bounds.size.width - 80;
    if (contentW != _lastContentWidth) {
        _lastContentWidth = contentW;
        CGRect textRect = [_remark boundingRectWithSize:CGSizeMake(contentW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil];
        if (textRect.size.height > 20) {
            _shouldShowxiaButton = YES;
        } else {
            _shouldShowxiaButton = NO;
        }
    }

在model中把高度計(jì)算出來。

3 滑動(dòng)過程中盡量減少重新布局
自動(dòng)布局就是給控件添加約束,約束最終還是轉(zhuǎn)換成frame。所以在滿足業(yè)務(wù)需求情況下,如果圖層層次較為復(fù)雜,要盡量減少自動(dòng)布局約束,轉(zhuǎn)為手動(dòng)計(jì)算布局,大量的約束重疊也會(huì)增加cpu的計(jì)算量。

按需加載
// 按需加載 - 如果目標(biāo)行與當(dāng)前行相差超過指定行數(shù),只在目標(biāo)滾動(dòng)范圍的前后指定3行加載。
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    NSIndexPath *ip = [self.tableView indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];   // 停止拖拽后,預(yù)計(jì)滑動(dòng)停止后到的偏移量
    NSIndexPath *cip = [[self.tableView indexPathsForVisibleRows] firstObject]; // 當(dāng)前可視區(qū)域內(nèi) cell 組
    NSInteger skipCount = 8;
    NSLog(@"targetContentOffset = %f",targetContentOffset->y);
    NSLog(@"indexPathForRowAtPoint = %@",ip);
    NSLog(@"visibleRows = %@",[self.tableView indexPathsForVisibleRows]);
    if (labs(cip.row - ip.row) > skipCount) {   // labs-返回 x 的絕對值,進(jìn)入該方法,說明滑動(dòng)太厲害了,預(yù)計(jì)停留位置與當(dāng)前可視區(qū)域范圍內(nèi)差 8 個(gè)cell 以上了.
        // 拖拽停止滑動(dòng)停止后,即將顯示的 cell 索引組
        NSArray *temp = [self.tableView indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, self.tableView.width, self.tableView.height)];
        NSMutableArray *arrM = [NSMutableArray arrayWithArray:temp];
        NSLog(@"temp = %@",temp);
        if (velocity.y < 0) {   // 向上滑動(dòng)-即加載更多數(shù)據(jù)
            NSIndexPath *indexPath = [temp lastObject];
            if (indexPath.row + 3 < self.dataSource.count) {    // 滑動(dòng)停止后出現(xiàn)的 cell 索引仍在數(shù)據(jù)源范圍之內(nèi)
                [arrM addObject:[NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0]];
                [arrM addObject:[NSIndexPath indexPathForRow:indexPath.row + 2 inSection:0]];
                [arrM addObject:[NSIndexPath indexPathForRow:indexPath.row + 3 inSection:0]];
            }
        } else {    // 向下滑動(dòng)-加載之前的數(shù)據(jù)
            NSIndexPath *indexPath = [temp firstObject];
            if (indexPath.row > 3) {
                [arrM addObject:[NSIndexPath indexPathForRow:indexPath.row - 3 inSection:0]];
                [arrM addObject:[NSIndexPath indexPathForRow:indexPath.row - 2 inSection:0]];
                [arrM addObject:[NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0]];
            }
        }
        
        [self.needLoadArray addObjectsFromArray:arrM];
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容