溫馨提示×

溫馨提示×

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

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

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

發(fā)布時(shí)間:2020-06-04 18:20:55 來源:網(wǎng)絡(luò) 閱讀:2485 作者:iKingLai 欄目:移動(dòng)開發(fā)

翻譯繼續(xù)進(jìn)行。。。


圖3-6中的UITableViewCell有4張圖片,還有一個(gè)不同顏色的subview。subview是開發(fā)者通常使用的一種方式,如果你想要一個(gè)不同的背景色或使內(nèi)部的view管理起來更加簡單的話。這種方法會(huì)導(dǎo)致table view滾動(dòng)時(shí)的性能問題,所以你應(yīng)該盡量避免使用它。


現(xiàn)在,讓我們來看一下使用新方法的源代碼,我自己繪制view,不再使用subview。你會(huì)看到用這種方法實(shí)現(xiàn)時(shí)需要做的工作,然后我會(huì)總結(jié)不同技術(shù)的優(yōu)點(diǎn)和缺點(diǎn)。示例源代碼來自DrawingCellViewController這個(gè)工程。下面是它的主要源代碼。


For UITableViewController:


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

   static NSString *CellIdentifier = @"CellIdentifier";

   CustomDrawingTableViewCell *cell = (CustomDrawingTableViewCell *)       [self.tableViewdequeueReusableCellWithIdentifier:CellIdentifier];

   if (cell == nil) {
   cell = [[CustomDrawingTableViewCell alloc]

initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}

   [cell updateMyCell];

  return cell;

}


正如你所看到的,UITableViewController的主要代碼并沒有變化。這個(gè)和標(biāo)準(zhǔn)的UITableViewCell的不同之處在于你是如何初始化你的cell。例如,


[[CustomDrawingTableViewCell alloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier];


相比


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


在自定義的UITableViewCell(例如,CustomDrawingTableViewCell)中


(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString

*)reuseIdentifier {
   if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]) {

           CGRect subFrame = CGRectMake(0.0, 0.0,

           self.contentView.bounds.size.width, self.contentView.bounds.size.height);

           drawingView = [[CustomDrawingView alloc] initWithFrame: subFrame];

           drawingView.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;

           [self.contentView addSubview:drawingView];

       }

       return self;

}


現(xiàn)在到了最重要的部分:如何繪制文本,圖片和在view中進(jìn)行控制。


CustomDrawingView.m


- (void)drawRect:(CGRect)rect {

       self.backgroundColor = [UIColor whiteColor];
       // Drawing code.
       [self.userName drawInRect:CGRectMake(70,0, 95, 21) withFont:userNameFont

lineBreakMode:UILineBreakModeTailTruncationalignment:UIBaselineAdjustmentAlignBaselines];

       // Drawing Image
       [self.avatarImage drawInRect:CGRectMake(20, 5, 36, 34)];

       // Drawing button

       [self.button drawInRect:CGRectMake(50, 5, 36, 34)];

}

簡而言之,在UITableViewController構(gòu)造一個(gè)自定義的UITableViewCell和之前是一樣的;你僅僅需要在在dequeue的時(shí)候判斷cell是否為nil,如果為nil就初始化一個(gè)新的對象。在初始化方法的內(nèi)部,你必須添加一個(gè)subview到cell的內(nèi)容中。對于subview,你需要復(fù)寫drawRect方法,然后drawInRect方法繪制文本或圖片。


自己繪制view的代碼之所以比從nib文件加載或用創(chuàng)建添加subview的方法快,最直接的原因是GPU(圖形處理單元)運(yùn)行了繪制代碼。GPU在渲染和顯示UI是非??斓?;因此,繪制代碼是處理復(fù)雜subviews的

最快的方法。


注意:非常重要的是設(shè)置CustomDrawingView的背景為白色。默認(rèn)是黑色的。



從這些例子中你能學(xué)到什么?


從上面的兩個(gè)例子中,你應(yīng)該記住一些基本的知識(shí)。

  • 使用ReuseIdentifier。它能幫助你提升性能。

  • 嘗試減少cell預(yù)加載過程中的工作,尤其是從文件IO或網(wǎng)絡(luò)IO加載圖片的時(shí)間和效率。這樣可以在最短的時(shí)間內(nèi)顯示圖片。

  • 如果你的應(yīng)用有很多的subviews或復(fù)雜的結(jié)構(gòu),考慮自己用代碼來繪制。這樣可以讓GPU來加速整個(gè)過程。



警告:從上面的測試結(jié)果可以看出,fps的結(jié)果變得越來越好,幾乎接近最理想的值60。但是,使用這種方法,你不能享有InterfaceBuilder構(gòu)建UI的好處。你總是要自己計(jì)算位置和大小,然后把這些信息放在drawRect方法中。這樣很快會(huì)導(dǎo)致維護(hù)和功能膨脹(在應(yīng)用中添加過多的功能)的問題。因此,謹(jǐn)慎使用drawRect,避免過多優(yōu)化。



其他技術(shù)


我已經(jīng)討論了table view 滾動(dòng)時(shí)提升性能的重要技術(shù)。還有其他一些小技術(shù)你通常是不需要使用的,但是在這里我也會(huì)介紹。如果你能理解這些概念,你可以把這些技術(shù)應(yīng)用到其他的情況下。


緩存高度


無論是否需要?jiǎng)?chuàng)建一個(gè)新的cell,你需要緩存rows的高度,因?yàn)檫@是TableView所需要的信息。如果你的cell的高度是固定的,你不必?fù)?dān)心。然而,如果它不是固定的,你需要確保你的cell計(jì)算足夠的快。


可以嘗試使用如下代碼:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {

   return 80;

}


避免使用下面的代碼:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {

for (int i = 0; i < 100; i++) {

// find the smallest possible height for the row

}

   return smallestHeight;

}


當(dāng)需要渲染cell或者在動(dòng)畫過程中需要編輯/重排序cell的時(shí)候,OS會(huì)多次運(yùn)行第一段代碼段。xiang像第二段代碼中有一個(gè)循環(huán),無論是否需要知道cell的高度,OS都會(huì)運(yùn)行一個(gè)重復(fù)100次的循環(huán)。


透明度


如果有可能,使UITableView所有的layers和subviews保持不透明。當(dāng)一個(gè)view是透明的,iOS需要渲染一個(gè)像素兩次或多次,這是因?yàn)橐粋€(gè)像素同時(shí)屬于很多subviews。這是一個(gè)非常耗時(shí)的過程。


通過代碼或者InterfaceBuilder能夠很簡單的做到。開發(fā)者應(yīng)該多次檢查所有的subviews是不透明的。圖3-7顯示了如何在cell中設(shè)置subview為不透明的checkbox。


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


對于自定義代碼,你可以通過代碼來設(shè)置,如下:


view.opaque = YES;



避免使用圖形特效


避免在UIImage中使用復(fù)雜的圖形特效(例如漸變)。你應(yīng)該對CoreAnimation進(jìn)行一些小的配置,然后使用它來檢查圖形特效,如圖3-8和3-9。

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


編輯/重排序 性能


在前面的部分,我展示了直接繪制的方法,你能夠顯著的優(yōu)化apps的性能。但是繪制的這種方法,在動(dòng)畫和重排序性能中,會(huì)有很多嚴(yán)重的問題。


當(dāng)你使用subviews的時(shí)候,動(dòng)畫會(huì)變的很快,在動(dòng)畫過程中UIKit不會(huì)重繪或修改任何東西。因此,對于UIKit來說,使用subview比自己通過代碼來繪制更快。如果在動(dòng)畫或重排序中,你通過代碼自己繪制view,你必須再一次繪制然后重新填充到新view中。這樣導(dǎo)致做了很多工作,包括代碼的創(chuàng)建和維護(hù)。


當(dāng)你在用UITableViewController遇到性能問題時(shí),你必須進(jìn)行一個(gè)權(quán)衡。我的建議是:如果你能確保不會(huì)有很多的subviews,或者你允許用戶對cell進(jìn)行編輯或重排序,那么就用subview這種方法。雖然可能會(huì)使得app運(yùn)行慢一些,但也已經(jīng)不錯(cuò)了。



總結(jié)


通過這里例子的源代碼分析,你已經(jīng)學(xué)會(huì)了很多提升性能的重要技術(shù)了。

  • 使用NSLog和CoreAnimation進(jìn)行仔細(xì)的測試:通過一個(gè)實(shí)際的例子,我讓你看到了如何使用Instrument和benchmark工具有效的理解問題的實(shí)質(zhì),以及在每一步優(yōu)化之后提升了多少性能。

  • 恰當(dāng)?shù)闹赜胏ell:這是第一步,也是最重要的一步。重用一個(gè)cell非常簡單,但是很多應(yīng)用都會(huì)漏了這一步。因此,你如果有很多性能問題,確保多次檢查這方面的問題。

  • 恰當(dāng)?shù)?緩存/重用 圖片/數(shù)據(jù):另外一個(gè)重要的步驟就是當(dāng)返回一個(gè)cell顯示的時(shí)候,減少數(shù)據(jù)加載和邏輯處理的時(shí)間。

  • 減少總的加載和計(jì)算時(shí)間:并不是僅僅只有IO會(huì)減慢和阻塞UI線程;任何數(shù)據(jù)的處理都會(huì)減慢這個(gè)過程。因此,你應(yīng)該總是盡可能的減少這個(gè)過程的處理時(shí)間。

  • 自行繪制cell:在渲染table view的時(shí)候,為了充分利用GPU計(jì)算密集型的優(yōu)勢,你應(yīng)該考慮使用直接繪制的方法。這樣會(huì)顯著的提升渲染的速度,增加測量的性能;fps幾乎接近最大。你可以通過復(fù)寫drawRect方法繪制自己的cell,然后在每個(gè)元素中調(diào)用不同的方法繪制每個(gè)UI元素。

  • 透明度:當(dāng)開發(fā)者將他們的UI元素放進(jìn)view的時(shí)候,這是經(jīng)常會(huì)遇到的小問題。如果他們沒有設(shè)置view為不透明,渲染的時(shí)候就要對同一個(gè)點(diǎn)繪制兩次或多次。

  • 緩存高度:這是開發(fā)者經(jīng)常會(huì)犯的另一個(gè)小錯(cuò)誤。每當(dāng)需要一個(gè)新的cell,每次都會(huì)有兩個(gè)主要的方法被調(diào)用。

  • 避免圖形特效:在cell中有越多的特效,渲染的過程就越慢。因此,你應(yīng)該對此進(jìn)行測試。你可以使用CoreAnimation來查看每個(gè)UI元素渲染的效率。

  • 編輯/重排序性能:滾動(dòng)性能優(yōu)化,對于編輯或重排序來說,可能會(huì)帶來一些問題,因?yàn)閁IKit和動(dòng)畫框架已經(jīng)多subview進(jìn)行了優(yōu)化。如果你是自己繪制的話,這些框架的優(yōu)化將不起作用。



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

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

AI