溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

UITableView性能提升和優(yōu)化(第3章) 之一

發(fā)布時間:2020-08-15 02:22:01 來源:網(wǎng)絡(luò) 閱讀:2891 作者:iKingLai 欄目:移動開發(fā)

在本章,你將做下面這些事情:


  • 在實例中使用第2章介紹的測試工具

  • 在例子中一步一步的對滾動性能進行優(yōu)化

  • 使用以下技術(shù)對UITableView進行優(yōu)化

             1)  使用基本的技術(shù)優(yōu)化UITableView中簡單的cells

             2)  通過代碼使用核心技術(shù)在cell中繪制view

             3)  使用基本的技術(shù)來優(yōu)化需要像正在編輯,重排序等動畫的cell

             4)  開發(fā)者需要知道的一些其他技術(shù)


iPhone應(yīng)用程序通常通過列表的形式來顯示數(shù)據(jù)。蘋果為開發(fā)者提供了非常好用的工具:UITableView 和 UITableViewCell。如果開發(fā)者只是想使用一些基本的功能,如在左邊顯示一張小圖片,中間顯示文本,那么蘋果提供的默認(rèn)控制就能夠很好的滿足要求了。但是如果你想自定義一些東西,比如顯示2張或3張圖片,把文本放在不同的地方,你就會遇到問題。如果這樣的話,你遲早會遇到UITableView性能方面的一些問題,尤其是在像iPhone 3G這種老設(shè)備上。


例子介紹


在這個例子中,我會基于兩個主要因素來衡量性能:UITableView dequeue一個cell,創(chuàng)建一個cell的速度,或cell返回給操作系統(tǒng)的速度;操作系統(tǒng)渲染你的cell,然后顯示在機器上的速度。第一個使用NSLog就可以測量出來;第二個比較復(fù)雜,只能通過CoreAnimation進行測量。


我將用兩個不同的例子來說明問題。一個只包含了圖片和文字;另一個包含了很多復(fù)雜的子view。通過這兩個例子,你會發(fā)現(xiàn)有很多不同的方法來優(yōu)化UITableView滾動時的性能。


在本章結(jié)束時,我會列出很多重要的知識點,由于時間有限,我不會做詳細(xì)的介紹。這些并不是一些常見的錯誤,但是如果某個開發(fā)者因為粗心而犯了其中的一些錯誤,有可能花上一整天的時間測試和查找問題。我想確保你已經(jīng)有足夠的技能和知識來處理各種情況。


有時候優(yōu)化非常簡單,只需要在代碼中做一些小小的改動。然而在其他情況下,比如第二個例子,你需要重寫整個代碼來,從而達到更好的性能。我希望在例子介紹完后,你對整個程序的架構(gòu)有一個非常清晰的認(rèn)識,這樣你在開始的時候就能夠做出正確的決定,而不需要重寫代碼。



復(fù)習(xí)測試工具


在本章,你將使用CoreAnimation工具對iphone OS的渲染性能進行測試。這能幫助你了解問題是出現(xiàn)在計算過程中還是在顯示過程中。第2章已經(jīng)介紹了這個工具,所以本章只進行一個簡短的回顧。


圖 3-1 顯示了CoreAnimation工具的主視圖,運行時有3個部分你需要觀察,圖3-2顯示了性能的參數(shù)值。


UITableView性能提升和優(yōu)化(第3章) 之一

圖 3-1 CoreAnimation 工具的主要部分


UITableView性能提升和優(yōu)化(第3章) 之一

圖 3-2 最近的性能顯示



第一個例子


第一個例子將會一步一步的展示如何優(yōu)化UITableView的滾動性能。最初版本的源代碼包含了我從很多開發(fā)者那邊搜集到的性能使用上的錯誤。在這個過程中,你會看到在每一步優(yōu)化后,性能都會有所提升。


介紹第一個例子


如圖3-3,你有一個普遍而又實際的問題,那就是你需要開發(fā)一個UITableView,在每一個cell中有一張圖片和一個文本塊。我將帶你查看這個例子的源代碼。讓我們看一下類似Facebook的應(yīng)用;應(yīng)用需要一張圖片顯示頭像,需要另一張圖片顯示用戶分享的鏈接內(nèi)容。這個應(yīng)用同樣也需要一張更小的圖片來顯示cell中的圖標(biāo)。在第一個測試中,請參考SlowPerformanceTableView這個工程。


UITableView性能提升和優(yōu)化(第3章) 之一

圖 3-3 第一個例子的應(yīng)用



標(biāo)準(zhǔn)測試


在項目開始之前,你必須知道你的最終目標(biāo);在這個例子中,你要達到的目標(biāo)就是有一個很好的性能,當(dāng)在滾動和使用你的應(yīng)用時,你可以帶給用戶一個很好的體驗。因此,通過運行一個正常的沒有自定義的UITableViewCell,它會按需加載一張簡單的圖片并會對圖片進行重用,表格 3-1顯示了運行時的日志。


UITableView性能提升和優(yōu)化(第3章) 之一

表格 3-1 運行例子的結(jié)果


用CoreAnimation進行測試,每秒渲染的幀數(shù)(fps)的最佳性能是60fps(數(shù)字越高,性能越好)。對于一個標(biāo)準(zhǔn)的UITableViewCell,通常的速度在 55-60fps之間;這應(yīng)該是你的目標(biāo)之一。另一個目標(biāo)是確保預(yù)加載的時間足夠的小。當(dāng)總體時間減少了,cell預(yù)加載的時間同樣會減少。但是,減少cell預(yù)加載的時間更簡單,因此在這個例子中,主要集中在如何減少預(yù)加載的時間。


初始化測試


在第一個例子中,我運行了一個初始化的測試,得到了6個cell滾動時的隨機結(jié)果。表格3-2顯示了測試性能的結(jié)果(使用了NSLog和CoreAnimation)。


UITableView性能提升和優(yōu)化(第3章) 之一

表格3-2 第一個例子初始化測試的結(jié)果


從結(jié)果中可以看出,繪制和返回一個cell通常需要10毫秒的時間。由于這個時間是非常巨大的,通常的測量(fps)同樣也會降低效率。因此,我的第一個目標(biāo)就是減少這個過程的預(yù)加載時間。


源代碼中有一個需要注意的地方:[UIImage p_w_picpathNamed:name]和[[UIImage alloc]initWithContentsOfFile:name] 之間的區(qū)別。稍后我會解釋他們的不同以及為什么用 p_w_picpathNamed代替initWithContentsOfFile。


重用UITableViewCell


優(yōu)化UITableView通常是非常簡單的;你需要做的就是檢查是否用正確的方式重用UITableViewCell。創(chuàng)建一個UITableViewCell對于iOS來說是一個CPU密集型的過程。因此,如果用戶上下滾動的時候每次都要創(chuàng)建一個新的cell,整個性能將會下降。蘋果的標(biāo)準(zhǔn)(默認(rèn))的方式就是:無論cell是否在屏幕之外,都重用這個cell,從而加速這個過程。


標(biāo)準(zhǔn)的UITableViewCell


對于標(biāo)準(zhǔn)的UITableViewCell,通用的代碼實際上可以工作的很好,能夠給你一個快速的滾動性能。

- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath {

       static NSString *CellIdentifier = @"Cell";
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

       if (cell == nil) {

           cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault         reuseIdentifier:CellIdentifier];

}

注意reuseIdentifier:CellIdentifier anddequeueReusableCellWithIdentifier:CellIdentifier的使用。這兩部分會幫助你正確的重用UITableViewCell。


有兩種主要的方法創(chuàng)建一個自定義的cell,要么使用InterfaceBuilder,要么通過調(diào)用addSubview:方法,然后自己寫代碼來創(chuàng)建。



使用 InterfaceBuilder創(chuàng)建自定義UITableView


當(dāng)使用InterfaceBuilder的時候,開發(fā)者通常會忘記設(shè)置identifier,實際上這個設(shè)置是非常簡單的。可以通過打開xib文件,轉(zhuǎn)到第一個tab,對第一行進行修改來改變identifier的值,如圖3-4。


UITableView性能提升和優(yōu)化(第3章) 之一

圖3-4 為cell設(shè)置重用的identifier


現(xiàn)在,在cell的初始化代碼中,你必須明確的使用相同的identifier。

- (UITableViewCell *)tableView:(UITableView *)tableViewcellForRowAtIndexPath:(NSIndexPath *)indexPath {

       static NSString *CellIdentifier = @"CellIdentifier"; // must match the one inInterfaceBuilder

       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) {

       cell = [[UITableViewCell alloc]     initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier];

}



通過代碼自定義UITableView


如果你不想用interfacebuilder,而是用代碼構(gòu)建自定義的cell,你可以在你自定義的類ReuseTableView中返回它。


TableCellViewController.h
@interface TableCellViewController : UITableViewCell

{

}
@end


TableCellViewController.m

#import "TableCellViewController.h"

@implementation TableCellViewController


- (NSString *)reuseIdentifier

{

       return @”CellIdentifier”;

}

@end



注意:這兩種方法的主要不同之處在于加載和初始化你的UITableView。確保你能夠理解這兩個例子的不同之處,我將會向你展示主要的代碼。



從Nib文件加載Cell


首先,你需要用代碼從文件系統(tǒng)中加載nib文件到內(nèi)存中,然后解析出給UITableView對象。


- (UITableViewCell *)cellWithTableView:(UITableView *)tableView cellIdentifier:(NSString*)cellIdentifier nibName:(NSString *)nibName {


   UITableViewCell *textCell = [tableViewdequeueReusableCellWithIdentifier:cellIdentifier];

   if (textCell == nil) {
         NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:nibName

         owner:niloptions:nil];

       for (id currentObject in topLevelObjects) {
             if ([currentObject isKindOfClass:[UITableViewCell class]]) {

                 textCell = (UITableViewCell *)currentObject;

                 break;

              }

        }

   }

 return textCell;

}


你可以使用以下代碼,調(diào)用cellWithTableView:cellIdentifier:nibName: 從nib TableViewController加載 stable view :


ReuseTableViewCell *cell = (ReuseTableViewCell *) [selfgetCellWithTableView:tableView

cellIdentifier:CellIdentifiernibName:@"ReuseTableViewCell"];


這個代碼不是完美的;你需要修改成你自己的nib文件確保一切運行順利。但是,我的目的是確保你能夠區(qū)分這兩種方式,所以我沒有討論過多的細(xì)節(jié)。


從自己的代碼中加載cell


- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier {

       self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

       if (self != nil) {

           UIImageView *p_w_picpathView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20,30, 30)];

       [self.contentView addSubview:p_w_picpathView];}

      return self;

}


給你一個小的練習(xí),創(chuàng)建一個新的工程,嘗試創(chuàng)建一個自定義的cell;你必須檢查所有的代碼確保你能夠正確的重用cell。



由于篇幅有限,今天暫時介紹到這里,明天繼續(xù)往下翻譯。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI