ios開發之解決重用TableViewCell導致的界面錯亂的問題


  無論是初學者,又或者是老鳥,只要是學習ios的人都知道,TableView對於開發有多重要,然而我們在使用TableView,可能會遇到各種各樣的問題,例如今天我想要說的 TableViewCell的重用的問題:

  我們都知道,在TableView返回每一行cell的數據源方法中,我們一般會通過重用cell來達到節省內存的目的:通過為每個cell指定一個重用標識符(reuseIdentifier),即指定了單元格的種類,當cell滾出屏幕時,會將滾出屏幕的單元格放入重用的緩存池中,當某個未在屏幕上的單元格要顯示的時候,就從這個緩存池中取出單元格進行重用。

但對於多變的自定義cell,有時這種重用機制會出錯。我舉個簡單的例子,看下面的兩張圖片 

<1>正常顯示的圖片

 

 

<2>界面錯亂的圖片

通過比較以上兩張圖片 明顯可以看出 第二張圖片的界面顯示錯亂,原因很簡單 ,那就是在重用cell的時候出現了問題,那么我們該怎么解決界面錯亂或者其他的問題呢?下面我一一為大家來介紹:

 

方法1 :

將獲得cell的方法從- (UITableViewCell*)dequeueReusableCellWithIdentifier:(NSString*)identifier 換為-(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath

重用機制調用的就是dequeueReusableCellWithIdentifier這個方法,方法的意思就是“出列可重用的cell”,因而只要將它換為cellForRowAtIndexPath(只從要更新的cell的那一行取出cell),就可以不使用重用機制,因而問題就可以得到解決,雖然可能會浪費一些空間。

//下面是示例代碼:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    static NSString *CellIdentifier = @"Cell"; 
    // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //改為以下的方法 
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //根據indexPath准確地取出一行,而不是從cell重用隊列中取出 
    if (cell == nil) { 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 

}......

上面的代碼,無疑是能夠解決界面錯亂的問題,但如果數據很多,那就會浪費相當多的空間,不推薦使用。

 

方法2:

為每個cell指定不同的重用標識符(reuseIdentifier)來解決。
重用機制是根據相同的標識符來重用cell的,標識符不同的cell不能彼此重用。於是我們將每個cell的標識符都設置為不同,就可以避免不同cell重用的問題了。

怎么為每個cell都設置不同的標示符呢?其實很簡單 在返回每一行cell的數據源方法中 通過為每一個cell的標示符綁定indexPath.section--indexPath.row就可以了,下面是示例代碼:

//實現建立cell的具體內容

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    

    static NSString * ID = [NSString stringWithFormat:@"cell-ld%-ld%",[indexPath section ],[indexPath row]];

    //2.到緩存池中去查找可重用標示符

    HMWeiboCell * cell = [tableView dequeueReusableCellWithIdentifier:ID];

    if (cell == nil) {

        cell = [[HMWeiboCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];

    }

    //給cell中得屬性framemodel賦值

    HMWeiboFrameModel * frameModel = self.weiboFrameArray[indexPath.row];

    cell.weiboFrameModel = frameModel;

    return cell;

}

//上面的這種方式 雖然說比第一種方式有了一定的改進,通過為每一個cell都綁定了一個不同的標識符能夠使得cell與cell之間不會重用,解決了界面錯亂的問題,但是從根本上來說還是沒有太大的內存優化,同樣的如果數據比較多還是比較浪費空間。

 

方法3:

 

  第三種方式其實很簡單就是刪除重用cell的所有子視圖,這句話什么意思呢?當我們從緩存池中取得重用的cell后,通過刪除重用的cell的所有子視圖,從而得到一個沒有特殊格式的cell,供其他cell重用。是不是還是沒懂什么意思,那我們就接着來看代碼:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    static NSString *ID = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; //出列可重用的cell

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];

    }

    else

    {

        //刪除cell的所有子視圖

        while ([cell.contentView.subviews lastObject] != nil)

        {

            [(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];//強制裝換為UIView類型 ,移除所有子視圖

        }

    }

    return cell;

}  

  看完上面的代碼是不是感覺這種方式很新穎,這種方式相比前兩種方式來說 是比較完美的,既達到了重用的目的,又不會導致界面的錯亂等問題,如果你也遇到了 自定義cell的時候 界面錯亂不堪,不妨試試這種方式吧,你會覺得很神奇的... 

 

方法4:

  看完了前面三種方式,你是不是覺得就沒有后文了呢,你錯了,下面我再來說說第四種方式:

  這第四種方式其實是比較笨的方法,為什么這么說呢,我們可以這么來想,既然重用cell導致界面錯亂的原因是,重用cell的時候 數據沒有更換,將重用cell的數據一起重用了,那么我們為什么想不到在給自定義cell設置數據的時候 通過判斷每一個cell該使用什么樣的數據呢 ,如果每一個cell使用的數據是不同的,那么就不會導致界面的數據或者是frame出現問題了,下面我就用簡單的的例子來為大家演示:

 

    //如果是某一個軟件的會員 那么會員圖標的frame設置 如果不是會員那么重新設置 這樣就能夠解決會員圖標的數據和frame問題

    if (weiboModel.vip) {//如果是會員

        CGFloat vipX = CGRectGetMaxX(_nameF) + kMargin;

        _vipF = CGRectMake(vipX, kMargin, kVipWidth, kVipWidth);

    } else{

        _vipF = CGRectZero;

    }

再比如

    //設置picture的frame 注意也要判斷是否有picture

    if (weiboModel.picture.length>0) {//有圖片     

        CGFloat pictureY = CGRectGetMaxY(_textF) + kMargin;

        _pictureF = CGRectMake(kMargin, pictureY, kPictureWidth, kPictureWidth);

        //如果有圖片行高就是最大的圖片的y值加一個邊距

        self.cellHeight = CGRectGetMaxY(_pictureF) + kMargin;

    }else {

        _pictureF = CGRectZero;   

        //如果沒有圖片 最大的行高就是正文的最大高度加一個高度

        self.cellHeight = CGRectGetMaxY(_textF) + kMargin;

    } 上面這句代碼的目的是 當有圖片的時候 給圖片設置frame  如果沒有圖片那么我們就設置frame為0,這樣就能輕松的解決frame導致的界面錯亂的問題了。

  以上四種方式,有自己的拙見,也有借鑒網上各位大牛的方法,希望這篇文章能夠對大家有幫助,有什么問題可以留言,我定將知無不言,言無不盡....


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM