天天看點

這些年對tableview的cell重用的誤解

不管是剛開始學,還是現在網上一些資料,都講明了

UITableView

重用

cell

的原理,以及好處。但是,有的地方沒有細講,導緻了我(可能也有你)對重用造成了誤解。

先說下我的誤解:我之前認為

cell

的重用,就是對記憶體進行了優化,不用建立很多個

cell

,造成記憶體消耗太多。

但是,最近我發現這種了解是錯誤的,而且是大錯特錯。下面先說明下結論:

cell

重用會造成更多的記憶體消耗。

當然了,空口無憑,事實說話。下面根據測試用例進行具體分析。測試用例可以在這裡下載下傳。

首先,測試用例包括幾種情況:

  1. 代碼建立

    UITableView

    ,代碼重用

    UITableViewCell

    / 代碼不重用

    UITableViewCell

  2. xib

    建立

    UITableViewController

    ,代碼重用

    UITableViewCell

    / 代碼不重用

    UITableViewCell

  3. storyboard

    建立

    UITableViewController

    UITableView

    content

    Static Cells

    /

    Dynamic Prototypes

    ,代碼重用

    UITableViewCell

    /

    storyboard

    重用

    UITableViewCell

    / 代碼不重用

    UITableViewCell

然後,我在

cell

内部作了一些操作:

  1. 建立一個靜态變量

    initCount

    ,用于表示

    cell

    建立的個數。
  2. 建立一個靜态變量

    deallocCount

    , 用于表示

    cell

    釋放的個數。
  3. dealloc

    方法中,清空

    initCount

    deallocCount

    ,以免影響下次的資料。

最後,就看測試資料了。

先看下每種情況下

cell

建立個數,銷毀個數。

  1. 使用代碼的情況下:
    • 重用時,建立 17 個,銷毀 17 個。
    • 不重用時,目前存在的最大個數為 17 個。以後伴随着滑動,cell 會繼續建立,當然也會繼續釋放,維持着最大為 17 個的狀态。
  2. 使用

    xib

    的情況下:

    跟第一種情況一樣。其實這種情況,隻有

    UITableView

    建立的方式不一樣,其他一樣。是以情況一樣也是正常的。
  3. 使用

    storyboard

    的情況下:

    UITableView

    content

    Dynamic Prototypes

    時:
    • 重用時,不管是代碼注冊重用,還是

      storyboard

      設定辨別重用,都是建立 16 個,銷毀 16 個。
    • 不重用時,目前存在的最大個數為 16 個。以後伴随着滑動,cell 會繼續建立,當然也會繼續釋放,維持着最大為 16 個的狀态。

    UITableView

    content

    Static Cells

    時:

    Dynamic Prototypes

    情況下是一樣的。

通過這些資料,基本上就知道了,即使

cell

不重用,也不會造成記憶體消耗太多。雖然每次都會建立新的

cell

,但是不需要的

cell

也會被銷毀。而且如上所說,不重用時,最大的個數與重用情況下一樣,是以不重用時的記憶體消耗最大情況下跟重用一樣,而且,當

cell

重用的時候,必定需要額外的操作存儲這些資料,是以,

cell

不重用時的記憶體是小于

cell

重用狀态下的。

即便是這樣,可能還是沒有說服力,下面具體看看使用代碼情況下重用與不重用的兩張圖。

這些年對tableview的cell重用的誤解
這些年對tableview的cell重用的誤解

注意,這裡由于

cell

比較簡單,是以我在

cell

初始化時,添加了一些資料,便于記憶體方面更加容易區分。

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        initCount++;
        NSLog(@"initCount -- %d", initCount);
        
        // 添加大資料,用于記憶體區分
        self.array = [NSMutableArray array];
        for (int i = 0; i < 100000; i++) {
            [_array addObject:@(i)];
        }
        
    }
    return self;
}
           

可以看到,重用時,記憶體為 24.6 M ;不重用時,記憶體為 24.0 M 。其他情況下,不再說明,有興趣下載下傳項目自己測試一下。

當然,這裡隻是考慮記憶體方面,其他方面,

cell

重用的優勢還是非常有效的。比如

cpu

fps

。在重用情況下,

cpu

的使用還是比較低的,

fps

也不會掉幀的。

其實,從緩存的角度講,緩存的存在就是使用存儲換時間,提高效率的。這裡

cell

的重用很明顯也是一種緩存。

cell

的重用,主要還是為了使清單滑動更加順暢,因為控件的建立消耗的時間還是比較大的。

但是,如果

cell

種類很多,而且不重複,那麼使用

cell

重用就沒有多大意義了。當然,如果這個頁面有很多幹貨,很多人會滑來滑去,還是有必要使用

cell

重用的,這樣,第二次開始滑動的流暢度就會明顯提高了。

上面隻是說了重用與不重用的差別,下面順便說下不同情況下,重用

cell

的差別。
  1. 不同方式建立

    UITableView

    情況下:
  • xib

    與 代碼 沒什麼差別
  • storyboard

    dynamic/static

    兩種情況不影響

    cell

    重用,

    static

    情況下,可以實作

    tableview

    的資料源方法,也可以不實作。如果沒有實作,

    cell

    的個數由

    storyboard

    中設定的值決定;如果實作了,

    cell

    個數由資料源決定的。
  1. 建立重用

    cell

    的差別。
  • 代碼、

    xib

    一樣,

    initWithStyle

    /

    registerClass

    兩種方式
  • stroyboard

    中,

    registerClass

    /

    storyboard

    cell

    加辨別兩種方式。
  1. 擷取重用cell的差別。
  • 代碼、

    xib

    一樣,都是代碼,如果使用

    initWithStyle

    建立 , 必須通過

    dequeueReusableCellWithIdentifier:

    方法擷取

    cell

    。 如果使用

    registerClass

    ,可以使用

    dequeueReusableCellWithIdentifier:

    或者

    dequeueReusableCellWithIdentifier:forIndexPath:

    兩種方式擷取

    cell

  • storyboard

    中,不管是代碼注冊

    cell

    ,還是

    storyboard

    中加

    cell

    辨別,都要使用

    dequeueReusableCellWithIdentifier:forIndexPath:

    擷取

    cell

  1. cell

    的初始化。

    當重用

    cell

    并且在

    storyboard

    中通過添加辨別重用

    cell

    時,

    cell

    建立時會調用

    awakeFromNib

    方法,其他情況下會調用

    initWithStyle:reuseIdentifier:

    方法。注意,這裡的

    cell

    不存在對應的

    xib

    檔案。

以上,就是最近對

UITableView

重用的新了解。其他沒有涉及的情況,有興趣可以自己動手試試,也可以向我的測試用例送出代碼。

繼續閱讀