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