cell的複用問題

       tableView是你們很是熟悉的一個控件,在絕大多數的界面上都有其身影,但就是這麼廣泛使用的控件,對於剛入行不深的小白也是有一些坑須要堤防,下面謹就我在開發過程當中遇到的cell複用問題作一下小結,狀況未必全面,但願讀者遇到有不一樣狀況的cell複用問題或者其餘任何問題均可與我交流,同努力,共交流,求提升!code

        有關cell的複用,基本就兩種狀況:orm

        一、系統原生的cell繼承

        二、自定義的cell隊列

        下面分狀況描述。圖片

一、系統原生的cell開發

        剛接觸iOS開發的時候就是用的這種,並且直到如今,稍微簡單點的cell用這種的也比較多,沒有單獨去建立一個cell類,直接在controller裏面就寫了,具體表現爲:rem

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
       UITableViewCell *cell = [tableView dequequedequeueReusableCellWithIdentifier:kCELLID];
       if (cell == nil){
           cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCELLID];
       }
       return cell;
}

那麼問題來了,加入說咱們要再cell上添加label或者圖片之類的應該怎麼作呢?label或者圖片應該在哪建立呢?更甚者有的人根本就沒有想過這個問題,只要效果出來了就不去探究了(我剛開始接觸的時候就是這種狀況),在這種狀況下建立其實也就兩種情形:博客

(1)
string

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 60, 20)];
        textLabel.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
        //還能夠設置label其餘的屬性等等.....
        
        [cell addSubview:textLabel];
    }
    
    
    return cell;
}

(2)it

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        
    }
    UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 60, 20)];
    textLabel.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row];
    //還能夠設置label其餘的屬性等等.....
    
    [cell addSubview:textLabel];
    
    return cell;
}

       這樣作以後,運行demo,剛開始看似正常,可是當tableView滾動的時候就出現了cell上label重疊的狀況,就出現了問題,第一種狀況是死活就出來屏幕上開始顯示的那些數據,滾動屏幕的時候並不會出現新的數據;第二種狀況滾動屏幕的時候每一個cell都有新的數據出現,但新出現的cell上出現了內容重疊的問題,即原來cell的內容並無消失,而直接在原來的基礎上增長了新的內容。出現這兩種狀況的緣由也很清楚:

        對於(1),很明顯咱們只建立了可以顯示在屏幕上的cell上的label,因此當cell剛展示未滾動前,結果是正常的,但當屏幕開始滾動的時候,根據cell的複用原理(第一個cell慢慢滾出屏幕,從屏幕底部將要出現的cell會先從複用隊列裏面尋找是否有可複用的cell,如有則直接拿來複用,若沒有從新建立),當開始複用時,因爲在建立cell時咱們已經給cell建立好了label,而且給label賦了值,因此新出現的cell的值都是以前在屏幕上已經出現cell的復現,就是把以前的cell不加任何修飾直接拿了過來,固然也就不可能有新的值出現;

        對於(2),在複用時,若是複用隊列裏面沒有咱們想要的cell,咱們只是單純的建立了一個cell,而把爲cell建立label和爲label賦值的操做則放在了每次展現cell的時候都會作的一個操做:

if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        
    }

在 if 裏面是每次去複用隊列裏面找不到的時候回採起的操做,在 if 的外面是每次展現cell的時候都會進行的而一個操做,因此這樣作也就意味着當咱們複用cell的時候,從複用隊列裏面取出來的cell上是含有label的,而咱們在原來的基礎智商又添加了一個label,就致使了兩個label的重疊。

        問題找到了,那麼應該符合解決呢?

對於(1)

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString * str = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:str];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:str];
        UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 60, 20)];
        textLabel.tag = 110;
        [cell addSubview:textLabel];
    }
    NSLog(@"%ld",indexPath.row);
    UILabel *textLabel = (UILabel *)[cell viewWithTag:110];
    textLabel.text = [NSString stringWithFormat:@"text %ld",indexPath.row];
    //還能夠設置label其餘的屬性等等.....
    
    
    return cell;
}

這樣寫就徹底解決了複用的問題,這個時候應該注意的是label的tag的設置,切忌不要寫成

textLabel.tag = 110 +indexPath.row;

由於當複用的時候 if 裏面的代碼不會再執行,而 if 外面還在用

UILabel *textLabel = (UILabel *)[cell viewWithTag:110 + indexPath.row];

去取label的話,取出的label確定爲nil,致使複用出得cell依然是隻有cell剛展示的時候的那部分數據。

        對於(2)

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString * str = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:str];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:str];
        
    }
    //每次展現cell的時候刪除cell上的內容,然後從新建立新的須要的內容
    for (UIView *view in cell.subviews) {
        [view removeFromSuperview];
    }
    UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 60, 20)];
    textLabel.text = [NSString stringWithFormat:@"text %ld",indexPath.row];
    //還能夠設置label其餘的屬性等等.....
    
    [cell addSubview:textLabel];
    return cell;
}

針對這種狀況就提一點:刪除cell上的內容有兩種:

for (UIView *view in cell.subviews) {
        [view removeFromSuperview];
    }

或者

for (UIView *view in cell.contentView.subviews) {
        [view removeFromSuperview];
    }

具體使用哪種應該看你是把label加到的哪一個上面若是add到了cell上則使用第一種,如果add到了cell.contentView 上就用第二種。


2. 自定義的cell

        對於較大或者較複雜的須要顯示的cell,咱們通常都會本身去定製,有多是咱們直接繼承一個UITableViewCell,用代碼去寫,也有多是用xib,不管用哪種狀況,複用的問題都比較好解決,只須要在系統的-(void)prepareForReuse 方法裏面去作複用前的操做就好了,好比將label上的內容置爲nil,將圖片置爲nil等等。

        這是我在項目中用到的,每次複用前作的操做。

-(void)prepareForReuse{
    self.icon.image = nil;
    self.title.text = nil;
    self.content.text = nil;
    self.time.text = nil;
    self.arrowImage.image = nil;
}

        純手敲,剛開始嘗試着寫博客,寫的有點囉嗦,條理可能也不是很清晰,但若是耐心來看的話複用這塊應該是沒什麼問題了,小白一個,但願你們多多支持,大神請繞過!

相關文章
相關標籤/搜索