標籤:
一、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的效能問題