您好,登錄后才能下訂單哦!
在本章,你將做下面這些事情:
在實例中使用第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ù)值。
圖 3-1 CoreAnimation 工具的主要部分
圖 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這個工程。
圖 3-3 第一個例子的應(yīng)用
標(biāo)準(zhǔn)測試
在項目開始之前,你必須知道你的最終目標(biāo);在這個例子中,你要達到的目標(biāo)就是有一個很好的性能,當(dāng)在滾動和使用你的應(yīng)用時,你可以帶給用戶一個很好的體驗。因此,通過運行一個正常的沒有自定義的UITableViewCell,它會按需加載一張簡單的圖片并會對圖片進行重用,表格 3-1顯示了運行時的日志。
表格 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)。
表格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。
圖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ù)往下翻譯。
免責(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)容。