UITableView
首先加載可以覆蓋一屏幕的 UITableViewCell
(具體個數要根據每一個 cell 的高度而定)。ui
而後當咱們往上滑動時(往下滑動同理),須要一個新的 cell 放置在列表的下方。此時,咱們不去生成新的 cell 而是先從 UITableView 的複用池裏去獲取,該池存放了已經生成的、可以複用的 cell ,若是該池爲空,纔會主動建立一個新的 cell 。spa
複用池的 cell 是這樣被添加至該池的:當咱們向上滑動視圖時(向下滑動同理),位於最頂部的 cell 會相應地往上運動,直至消失在屏幕上。當其消失在視圖中時,會被添加至當前 UITableView
的複用池。code
所以,在渲染海量數據的列表時,並不須要不少 cell ,這得益於 UITableView
的複用機制。orm
在使用 UITableView
時,咱們可使用 dequeueReusableCellWithIdentifier:
方法實現 cell 實例的複用。內存
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 定義 cell 標識。
static NSString *CellIdentifier = @"Cell";
// 從複用池獲取 cell 實例(可能爲空)。
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// 對 cell 進行簡單地數據配置.
// 偶數行的 title 文字顏色設置爲紅色。
if (indexPath.row % 2 == 0) {
[cell.titleLabel setTextColor:[UIColor redColor]];
cell.titleLabel.text = @"Title of Even Row";
} else {
cell.detailLabel.text = @"Detail";
}
return cell;
}
複製代碼
在上述代碼中,咱們但願偶數行的標題顏色設置爲紅色、標題內容爲 "Title of Even Row"、詳情內容爲空,但願奇數行的標題爲空、詳情內容爲 "Detail" 。開發
可是,當咱們滑動列表時,發現樣式錯亂了:偶數行的詳情內容不爲空、奇數行的標題不爲空。rem
該問題存在的根源在於 cell 實例的複用機制:當咱們沒有顯式地設置 cell 的樣式和內容時,它會繼續沿用回收前的樣式和內容設置。string
面對樣式錯亂的問題,咱們有這樣一種解決方法:在從複用池得到一個 cell 實例時,咱們須要顯示地設置它的全部樣式和內容。該方法確實可以解決問題,但對於開發人員來講,心智壓力是巨大的。it
咱們須要「心智壓力不那麼大」的解決方法。io
方案描述:取消 cell 的複用機制,每次渲染都選擇建立新的 cell 實例,將原有的 dequeueReusableCellWithIdentifier:
方法替換爲 cellForRowAtIndexPath:
。
缺點:沒法複用 cell ,在列表項較多時存在內存佔用過大的問題。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 定義 cell 標識。
static NSString *CellIdentifier = @"cell";
// 經過 indexPath 建立 cell 實例,使得對於不一樣的 indexPath ,
// 其對應的 cell 實例是不一樣的,從而解決問題。
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// 對 cell 進行簡單地數據配置.
// 偶數行的 title 文字顏色設置爲紅色。
if (indexPath.row % 2 == 0) {
[cell.titleLabel setTextColor:[UIColor redColor]];
cell.titleLabel.text = @"Title of Even Row";
} else {
cell.detailLabel.text = @"Detail";
}
return cell;
}
複製代碼
方案描述:爲每一個 cell 根據 indexPath
建立惟一的標識符。
缺點:雖然可複用 cell ,但在列表項較多時仍存在內存佔用過大的問題。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 根據 indexPath 定義 cell 標識。
NSString *CellIdentifier = [NSString stringWithFormat:@"cell%ld%ld",indexPath.section,indexPath.row];
// 從複用池獲取 cell 實例(可能爲空)。
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// 當複用池獲取的 cell 實例爲空時,須要建立新的 cell 實例。
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// 對 cell 進行簡單地數據配置.
// 偶數行的 title 文字顏色設置爲紅色。
if (indexPath.row % 2 == 0) {
[cell.titleLabel setTextColor:[UIColor redColor]];
cell.titleLabel.text = @"Title of Even Row";
} else {
cell.detailLabel.text = @"Detail";
}
return cell;
}
複製代碼
方案描述:每從複用池得到一個 cell 實例時,當其不爲空時,咱們須要刪除其全部的子視圖。
該方案可實現 cell 實例的複用,成功解決了問題,應該是最好的解決方案。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 定義 cell 標識。
static NSString *CellIdentifier = @"Cell";
// 從複用池獲取 cell 實例(可能爲空)。
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// 當複用池獲取的 cell 實例爲空時,須要建立新的 cell 實例。
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
} else {
// 當複用池獲取的 cell 實例不爲空時,刪除其全部子視圖,使其變「乾淨」。
while ([cell.contentView.subviews lastObject] != nil) {
[(UIView *)[cell.contentView.subviews lastObject] removeFromSuperview];
}
}
// 對 cell 進行簡單地數據配置.
// 偶數行的 title 文字顏色設置爲紅色。
if (indexPath.row % 2 == 0) {
[cell.titleLabel setTextColor:[UIColor redColor]];
cell.titleLabel.text = @"Title of Even Row";
} else {
cell.detailLabel.text = @"Detail";
}
return cell;
}
複製代碼