您好,登錄后才能下訂單哦!
翻譯繼續(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。
對于自定義代碼,你可以通過代碼來設(shè)置,如下:
view.opaque = YES;
避免使用圖形特效
避免在UIImage中使用復(fù)雜的圖形特效(例如漸變)。你應(yīng)該對CoreAnimation進(jìn)行一些小的配置,然后使用它來檢查圖形特效,如圖3-8和3-9。
編輯/重排序 性能
在前面的部分,我展示了直接繪制的方法,你能夠顯著的優(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)化將不起作用。
免責(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)容。