- 首先我們需要搞明白為什么要使用重用機制,它的原理是什么.
無論是UITableView還是UICollectionView,都有許多需要顯示的cell (item), 但是屏幕的大小是有限的,一次只能顯示那么幾個,如果我們把所有的數(shù)據(jù)全部都加載進去,暫時又看不到,就會非常浪費內(nèi)存. - 那么該如何避免這種不必要的內(nèi)存消耗呢?就是每次只顯示屏幕能放得下的cell的數(shù)據(jù),在用戶滑動屏幕的過程中,再去加載新的數(shù)據(jù),
- 于是就有了cell的重用機制
重用機制實現(xiàn)了數(shù)據(jù)和顯示的分離,并不會為每個要顯示的數(shù)據(jù)都創(chuàng)建一個Cell,一般情況下只創(chuàng)建屏幕可顯示的最大的cell個數(shù)+1,每當有一個cell從屏幕消失,就將其放到緩存池中,如果有新的cell出現(xiàn),就去緩存池中取,如果緩存池中沒有,再創(chuàng)建。
這種機制下系統(tǒng)默認有一個可變數(shù)組 NSMutableArray* visiableCells, 用來保存當前顯示的cell. 還有一個可變字典 NSMutableDictnery* reusableTableCells, 用來保存可重復利用的cell. 之所以用字典是因為可重用的cell有不止一種樣式,我們需要根據(jù)它的reuseIdentifier(重用標識符)來查找是否有可重用的該樣式的cell.
重用的寫法如下:
//設(shè)置單元格(cell) indexPath :單元格當前所在位置-哪一組的哪一行
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ //定義重用標識
static NSString *identifier = @"cell" ;
//identifier: 因為一個表視圖中可能存在多種樣式的單元格(cell),所以要相同樣式的單元格放到同一個集合里面,并且為這個 集合綁定標識符,當我們需要用到某種樣式的單元格的時候,就根據(jù)不同的標識符,從不同的集合中找尋單元格.
//該方法會先去緩存池中尋找對應(yīng)的cell 如果緩存池中沒有,就看有沒有注冊對應(yīng)的cell,如果也沒有注冊,就看storyboard中有沒 有綁定對應(yīng)標識的cell 都沒有的話就創(chuàng)建
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier] ;
if (!cell) {
//創(chuàng)建cell的時候需要標示符(Identifier)是因為,當該cell離開屏幕的時候需要根據(jù)標示符放到對應(yīng)的集合中.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
return cell ;
}
- 系統(tǒng)第一次執(zhí)行 cellForRowAtIndexPath:(NSIndexPath *)indexPath的時候, reusableTableCells為空,
[tableView dequeueReusableCellWithIdentifier:identifier] 的返回值為nil, 我們需要通過 initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: identifier] 方式來創(chuàng)建.
當我們的數(shù)據(jù)過多,整個屏幕的cell顯示不完全時,這個方法的執(zhí)行情況是 :
(1) 先執(zhí)行initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: identifier]創(chuàng)建整個屏幕能顯示的cell數(shù)+1的cell (當我們拖動屏幕的時候,第一個cell沒有移出屏幕,最下面的cell就已經(jīng)存在), 并指定相同或者不同的標示符identifier.把創(chuàng)建出的屏幕能顯示的cell全部都加入到visiableCells數(shù)組中(最后一個創(chuàng)建的先不加入數(shù)組),reusableTableCells為空.
(2)當我們拖動屏幕時,頂端的cell移出屏幕并加入到reusableTableCells字典中,鍵為identifier ,并把之前已經(jīng)創(chuàng)建的但是沒有加入到visiableCells的cell加入到visiableCells數(shù)組中.
(3)當我們接著拖動的時候,因為reusableTableCells中已經(jīng)有值,當需要顯示新的cell,cellForRowAtIndexPath再次被調(diào)用執(zhí)行[tableView dequeueReusableCellWithIdentifier: identifier],返回一個標示符為identifier的cell。該cell移出reusableTableCells之后加入到visiableCells;頂端的cell移出visiableCells并加入到reusableTableCells.如果visiableCells數(shù)組中沒有找到identifier類型的cell,則再次重新alloc一個.
在iOS6之后系統(tǒng)加入了一種單元格注冊的方法.
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier: identifier] ;
這個方法的作用是,當我們從重用隊列中取cell的時候,如果沒有,系統(tǒng)會幫我們創(chuàng)建我們給定類型的cell,如果有,則直接重用. 這種方式cell的樣式為系統(tǒng)默認樣式.
在設(shè)置cell的方法中只需要:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 重用隊列中取單元格 由于上面已經(jīng)注冊過單元格,系統(tǒng)會幫我們做判斷,不用再次手動判斷單元格是否存在
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: identifier forIndexPath:indexPath] ;
return cell ;
}