您好,登錄后才能下訂單哦!
翻譯繼續進行。。。
圖3-6中的UITableViewCell有4張圖片,還有一個不同顏色的subview。subview是開發者通常使用的一種方式,如果你想要一個不同的背景色或使內部的view管理起來更加簡單的話。這種方法會導致table view滾動時的性能問題,所以你應該盡量避免使用它。
現在,讓我們來看一下使用新方法的源代碼,我自己繪制view,不再使用subview。你會看到用這種方法實現時需要做的工作,然后我會總結不同技術的優點和缺點。示例源代碼來自DrawingCellViewController這個工程。下面是它的主要源代碼。
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的主要代碼并沒有變化。這個和標準的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;
}
現在到了最重要的部分:如何繪制文本,圖片和在view中進行控制。
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構造一個自定義的UITableViewCell和之前是一樣的;你僅僅需要在在dequeue的時候判斷cell是否為nil,如果為nil就初始化一個新的對象。在初始化方法的內部,你必須添加一個subview到cell的內容中。對于subview,你需要復寫drawRect方法,然后drawInRect方法繪制文本或圖片。
自己繪制view的代碼之所以比從nib文件加載或用創建添加subview的方法快,最直接的原因是GPU(圖形處理單元)運行了繪制代碼。GPU在渲染和顯示UI是非常快的;因此,繪制代碼是處理復雜subviews的
最快的方法。
注意:非常重要的是設置CustomDrawingView的背景為白色。默認是黑色的。 |
從這些例子中你能學到什么?
從上面的兩個例子中,你應該記住一些基本的知識。
使用ReuseIdentifier。它能幫助你提升性能。
嘗試減少cell預加載過程中的工作,尤其是從文件IO或網絡IO加載圖片的時間和效率。這樣可以在最短的時間內顯示圖片。
如果你的應用有很多的subviews或復雜的結構,考慮自己用代碼來繪制。這樣可以讓GPU來加速整個過程。
警告:從上面的測試結果可以看出,fps的結果變得越來越好,幾乎接近最理想的值60。但是,使用這種方法,你不能享有InterfaceBuilder構建UI的好處。你總是要自己計算位置和大小,然后把這些信息放在drawRect方法中。這樣很快會導致維護和功能膨脹(在應用中添加過多的功能)的問題。因此,謹慎使用drawRect,避免過多優化。 |
其他技術
我已經討論了table view 滾動時提升性能的重要技術。還有其他一些小技術你通常是不需要使用的,但是在這里我也會介紹。如果你能理解這些概念,你可以把這些技術應用到其他的情況下。
緩存高度
無論是否需要創建一個新的cell,你需要緩存rows的高度,因為這是TableView所需要的信息。如果你的cell的高度是固定的,你不必擔心。然而,如果它不是固定的,你需要確保你的cell計算足夠的快。
可以嘗試使用如下代碼:
- (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;
}
當需要渲染cell或者在動畫過程中需要編輯/重排序cell的時候,OS會多次運行第一段代碼段。xiang像第二段代碼中有一個循環,無論是否需要知道cell的高度,OS都會運行一個重復100次的循環。
透明度
如果有可能,使UITableView所有的layers和subviews保持不透明。當一個view是透明的,iOS需要渲染一個像素兩次或多次,這是因為一個像素同時屬于很多subviews。這是一個非常耗時的過程。
通過代碼或者InterfaceBuilder能夠很簡單的做到。開發者應該多次檢查所有的subviews是不透明的。圖3-7顯示了如何在cell中設置subview為不透明的checkbox。
對于自定義代碼,你可以通過代碼來設置,如下:
view.opaque = YES;
避免使用圖形特效
避免在UIImage中使用復雜的圖形特效(例如漸變)。你應該對CoreAnimation進行一些小的配置,然后使用它來檢查圖形特效,如圖3-8和3-9。
編輯/重排序 性能
在前面的部分,我展示了直接繪制的方法,你能夠顯著的優化apps的性能。但是繪制的這種方法,在動畫和重排序性能中,會有很多嚴重的問題。
當你使用subviews的時候,動畫會變的很快,在動畫過程中UIKit不會重繪或修改任何東西。因此,對于UIKit來說,使用subview比自己通過代碼來繪制更快。如果在動畫或重排序中,你通過代碼自己繪制view,你必須再一次繪制然后重新填充到新view中。這樣導致做了很多工作,包括代碼的創建和維護。
當你在用UITableViewController遇到性能問題時,你必須進行一個權衡。我的建議是:如果你能確保不會有很多的subviews,或者你允許用戶對cell進行編輯或重排序,那么就用subview這種方法。雖然可能會使得app運行慢一些,但也已經不錯了。
總結
通過這里例子的源代碼分析,你已經學會了很多提升性能的重要技術了。
使用NSLog和CoreAnimation進行仔細的測試:通過一個實際的例子,我讓你看到了如何使用Instrument和benchmark工具有效的理解問題的實質,以及在每一步優化之后提升了多少性能。
恰當的重用cell:這是第一步,也是最重要的一步。重用一個cell非常簡單,但是很多應用都會漏了這一步。因此,你如果有很多性能問題,確保多次檢查這方面的問題。
恰當的 緩存/重用 圖片/數據:另外一個重要的步驟就是當返回一個cell顯示的時候,減少數據加載和邏輯處理的時間。
減少總的加載和計算時間:并不是僅僅只有IO會減慢和阻塞UI線程;任何數據的處理都會減慢這個過程。因此,你應該總是盡可能的減少這個過程的處理時間。
自行繪制cell:在渲染table view的時候,為了充分利用GPU計算密集型的優勢,你應該考慮使用直接繪制的方法。這樣會顯著的提升渲染的速度,增加測量的性能;fps幾乎接近最大。你可以通過復寫drawRect方法繪制自己的cell,然后在每個元素中調用不同的方法繪制每個UI元素。
透明度:當開發者將他們的UI元素放進view的時候,這是經常會遇到的小問題。如果他們沒有設置view為不透明,渲染的時候就要對同一個點繪制兩次或多次。
緩存高度:這是開發者經常會犯的另一個小錯誤。每當需要一個新的cell,每次都會有兩個主要的方法被調用。
避免圖形特效:在cell中有越多的特效,渲染的過程就越慢。因此,你應該對此進行測試。你可以使用CoreAnimation來查看每個UI元素渲染的效率。
編輯/重排序性能:滾動性能優化,對于編輯或重排序來說,可能會帶來一些問題,因為UIKit和動畫框架已經多subview進行了優化。如果你是自己繪制的話,這些框架的優化將不起作用。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。