iOS開發UI篇—UITableviewcell的效能問題

來源:互聯網
上載者:User

標籤:

一、UITableviewcell的一些介紹

UITableView的每一行都是一個UITableViewCell,通過dataSource的 tableView:cellForRowAtIndexPath:方法來初始化每?行

UITableViewCell內部有個預設的子視圖:contentView,contentView是UITableViewCell所顯示內容的父視圖,可顯示一些輔助指示視圖

輔助指示視圖的作?是顯示一個表示動作的表徵圖,可以通過設定UITableViewCell的 accessoryType來顯示,預設是UITableViewCellAccessoryNone(不顯?示輔助指?示視圖), 其他值如下:

UITableViewCellAccessoryDisclosureIndicator

UITableViewCellAccessoryDetailDisclosureButton

UITableViewCellAccessoryCheckmark

還可以通過cell的accessoryView屬性來自訂輔助指示視圖(?如往右邊放一個開關) 

 

二、問題

  cell的工作:在程式執行的時候,能看到多少條,它就建立多少條資料,如果視圖滾動那麼再建立新顯示的內容。(系統自動調用)。即當一個cell出現在視野範圍內的時候,就會調用建立一個cell。這樣的邏輯看上去沒有什麼問題,但是真的沒有任何問題嗎?

  當建立調用的時候,我們使用NSlog列印訊息,並列印建立的cell的地址。我們發現如果資料量非常大,使用者在短時間內來復原動的話,那麼會建立大量的cell,一直開闢空間,且如果是往復原,通過列印地址,我們會發現它並沒有重用之前已經建立的cell,而是重新建立,開闢新的儲存空間。

  那有沒有什麼好的解決辦法呢?

 

三、cell的重用原理

(1) iOS裝置的記憶體有限,如果用UITableView顯示成千上萬條資料,就需要成千上萬個UITableViewCell對象的話,那將會耗盡iOS裝置的記憶體。要解決該問題,需要重用UITableViewCell對象

(2)重?原理:當滾動列表時,部分UITableViewCell會移出視窗,UITableView會將視窗外的UITableViewCell放入一個對象池中,等待重用。當UITableView要求dataSource返回 UITableViewCell時,dataSource會先查看這個對象池,如果池中有未使用的 UITableViewCell,dataSource則會用新的資料來配置這個UITableViewCell,然後返回給 UITableView,重新顯示到視窗中,從而避免建立新對象。這樣可以讓建立的cell的數量維持在很低的水平,如果一個視窗中只能顯示5個cell,那麼cell重用之後,只需要建立6個cell就夠了。

(3)注意點:還有?個非常重要的問題:有時候需要自訂UITableViewCell(用?個子類繼承UITableViewCell),而且每?行?的不一定是同一種UITableViewCell,所以一 個UITableView可能擁有不同類型的UITableViewCell,對象池中也會有很多不同類型的UITableViewCell,那麼UITableView在重?用UITableViewCell時可能會得到錯誤類型的UITableViewCell

解決?方案:UITableViewCell有個NSString *reuseIdentifier屬性,可以在初始化UITableViewCell的時候傳入一個特定的字串標識來設定reuseIdentifier(一般用UITableViewCell的類名)。當UITableView要求dataSource返回UITableViewCell時,先通過一個字串標識到對象池中尋找對應類型的UITableViewCell對象。如果有,就重用。如果沒有,就傳入這個字串標識來初始化一個UITableViewCell對象。

圖片樣本:

 

  說明:一個視窗放得下(可視)三個cell,整個程式只需要建立4個該類型的cell即可。

 

四、cell的最佳化代碼

   程式碼範例:

 1 #import "NJViewController.h" 2 #import "NJHero.h" 3  4 // #define ID @"ABC" 5  6 @interface NJViewController ()<UITableViewDataSource, UITableViewDelegate> 7 /** 8  *  儲存所有的英雄資料 9  */10 @property (nonatomic, strong) NSArray *heros;11 @property (weak, nonatomic) IBOutlet UITableView *tableView;12 13 @end14 15 @implementation NJViewController16 17 #pragma mark - 懶載入18 - (NSArray *)heros19 {20     if (_heros == nil) {21         // 1.獲得全路徑22         NSString *fullPath =  [[NSBundle mainBundle] pathForResource:@"heros" ofType:@"plist"];23         // 2.更具全路徑載入資料24         NSArray *dictArray = [NSArray arrayWithContentsOfFile:fullPath];25         // 3.字典轉模型26         NSMutableArray *models = [NSMutableArray arrayWithCapacity:dictArray.count];27         for (NSDictionary *dict in dictArray) {28             NJHero *hero = [NJHero heroWithDict:dict];29             [models addObject:hero];30         }31         // 4.賦值資料32         _heros = [models copy];33     }34     // 4.返回資料35     return _heros;36 }37 38 - (void)viewDidLoad39 {40     [super viewDidLoad];41     // 設定Cell的高度42     // 當每一行的cell高度一致的時候使用屬性設定cell的高度43     self.tableView.rowHeight = 160;44 }45 46 #pragma mark - UITableViewDataSource47 // 返回多少組48 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView49 {50     return 1;51 }52 // 返回每一組有多少行53 - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section54 {55     return self.heros.count;56 }57 // 當一個cell出現視野範圍內的時候就會調用58 // 返回哪一組的哪一行顯示什麼內容59 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath60 {61     // 定義變數儲存重用標記的值62     static NSString *identifier = @"hero";63     64 //    1.先去緩衝池中尋找是否有滿足條件的Cell65     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];66 //    2.如果緩衝池中沒有合格cell,就自己建立一個Cell67     if (cell == nil) {68         //    3.建立Cell, 並且設定一個唯一的標記69         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];70         NSLog(@"建立一個新的Cell");71     }72 //    4.給cell設定資料73     NJHero *hero = self.heros[indexPath.row];74     cell.textLabel.text = hero.name;75     cell.detailTextLabel.text = hero.intro;76     cell.imageView.image = [UIImage imageNamed:hero.icon];77     78    //  NSLog(@"%@ - %d - %p", hero.name, indexPath.row, cell);79     80     // 3.返回cell81     return cell;82 }83 84 #pragma mark - 控制狀態列是否顯示85 /**86  *   返回YES代表隱藏狀態列, NO相反87  */88 - (BOOL)prefersStatusBarHidden89 {90     return YES;91 }92 @end

緩衝最佳化的思路:

(1)先去緩衝池中尋找是否有滿足條件的cell,若有那就直接拿來

(2)若沒有,就自己建立一個cell

(3)建立cell,並且設定一個唯一的標記(把屬於“”的給蓋個章)

(4)給cell設定資料

注意點:

定義變數用來儲存重用標記的值,這裡不推薦使用宏(#define來處理),因為該變數只在這個範圍的內部使用,且如果使用宏定義的話,定義和使用位置太分散,不利於閱讀程式。由於其值不變,沒有必要每次都開闢一次,所以用static定義為一個靜態變數。

iOS開發UI篇—UITableviewcell的效能問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.