Objective-C: ячейки UITableView записываются каждый раз при прокрутке вверх и вниз - PullRequest
3 голосов
/ 22 декабря 2009

У меня есть UITableView, который заполняется через CoreData , и только что заметил что-то странное. У меня около 20 строк или около того в UITable, и когда я прокручиваю таблицу вниз и снова поднимаюсь вверх, метка ячейки записывается поверх существующего текста и продолжает делать это каждый раз, когда я спускаюсь и поднимаюсь снова. Мой код для CellForRowAtIndexPath:

  // Customize the appearance of table view cells.
  - (UITableViewCell *)tableView:(UITableView *)tableView   cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Some constants ---
const NSInteger TOP_LABEL_TAG = 1001;
const NSInteger BOTTOM_LABEL_TAG = 1002;
UILabel *topLabel;
UILabel *bottomLabel;
const CGFloat LABEL_HEIGHT = 20;
//CGRect Imageframe = CGRectMake(7, 5, 35, 35);
//----



static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.textLabel.font = [UIFont boldSystemFontOfSize:12];
}

//custom implementation of UIView for lazy loading of image 
//LazyUIImageView *lazy = [[LazyUIImageView alloc] initWithFrame:Imageframe];


//[cell addSubview:lazy];



Post *post = [fetchedResultsController objectAtIndexPath:indexPath];

NSSet *medias = post.PostMedia;
Media *media = [medias anyObject];
NSSet *thumbs  = media.MediaThumb;
Thumb *thumb = [thumbs anyObject];


UIImage *img = thumb.url;

if (img)
    cell.imageView.image = img;
else 
    cell.imageView.image = post.authorpic;

//The creation of the top label
topLabel =
[[[UILabel alloc]
  initWithFrame:
  CGRectMake(
             35 + 2.0 * cell.indentationWidth,
             0.5 * (tableView.rowHeight - 2 * LABEL_HEIGHT),
             tableView.bounds.size.width -
             45 - 4.0 * cell.indentationWidth
             - 35,
             LABEL_HEIGHT)]
 autorelease];
[cell.contentView addSubview:topLabel];

topLabel.tag = TOP_LABEL_TAG;
topLabel.backgroundColor = [UIColor clearColor];
topLabel.textColor = [UIColor colorWithRed:0.25 green:0.0 blue:0.0 alpha:1.0];
topLabel.highlightedTextColor = [UIColor colorWithRed:1.0 green:1.0 blue:0.9 alpha:1.0];
topLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
//---------------------------------

//The creation of the bottom label
bottomLabel =
[[[UILabel alloc]
  initWithFrame:
  CGRectMake(
             35 + 2.0 * cell.indentationWidth,
             0.5 * (tableView.rowHeight - 2 * LABEL_HEIGHT) + LABEL_HEIGHT,
             tableView.bounds.size.width -
             35 - 4.0 * cell.indentationWidth
             - 35,
             LABEL_HEIGHT)]
 autorelease];
[cell.contentView addSubview:bottomLabel];
//--------------------------------

//
// Configure the properties for the text that are the same on every row
//
bottomLabel.tag = BOTTOM_LABEL_TAG;
bottomLabel.backgroundColor = [UIColor clearColor];
bottomLabel.textColor = [UIColor colorWithRed:0.25 green:0.0 blue:0.0 alpha:1.0];
bottomLabel.highlightedTextColor = [UIColor colorWithRed:1.0 green:1.0 blue:0.9 alpha:1.0];
bottomLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];

//
// Create a background image view.
//
cell.backgroundView =
[[[UIImageView alloc] init] autorelease];
cell.selectedBackgroundView =
[[[UIImageView alloc] init] autorelease];;


topLabel.text = post.title;
bottomLabel.text = @"put something here";


//
// Set the background and selected background images for the text.
// Since we will round the corners at the top and bottom of sections, we
// need to conditionally choose the images based on the row index and the
// number of rows in the section.
//
UIImage *rowBackground;
UIImage *selectionBackground;
NSInteger sectionRows = [tableView numberOfRowsInSection:[indexPath section]];
NSInteger row = [indexPath row];
if (row == 0 && row == sectionRows - 1)  //all
{
    rowBackground = [UIImage imageNamed:@"topAndBottomRow.png"];
    selectionBackground = [UIImage imageNamed:@"topAndBottomRowSelected.png"];
}
else if (row == 0) //top
{
    rowBackground = [UIImage imageNamed:@"topRow.png"];
    selectionBackground = [UIImage imageNamed:@"topRowSelected.png"];
}
else if (row == sectionRows - 1) //bottom
{
    rowBackground = [UIImage imageNamed:@"bottomRow.png"];
    selectionBackground = [UIImage imageNamed:@"bottomRowSelected.png"];
}
else //middle
{
    rowBackground = [UIImage imageNamed:@"middleRow.png"];
    selectionBackground = [UIImage imageNamed:@"middleRowSelected.png"];
}
((UIImageView *)cell.backgroundView).image = rowBackground;
((UIImageView *)cell.selectedBackgroundView).image = selectionBackground;


//[lazy release];

return cell;

}

Заранее спасибо за помощь!

Ответы [ 5 ]

8 голосов
/ 22 декабря 2009

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Эта строка говорит вашему приложению повторно использовать существующие внеэкранные ячейки, если они существуют. Таким образом, вы берете уже существующую ячейку и добавляете в нее новое подпредставление в том же месте, в котором оно уже завершено. Вам нужно очистить существующие подпредставления перед добавлением нового подпредставления.

Обновление в ответ на ваш комментарий:

код jan удалит существующие подпредставления. Вы добавили бы его в свой код выше как условие else вашего оператора if cell is nil.

Таким образом, если у вас нет доступной для повторного использования ячейки (ячейка == ноль), ваш код создаст новую, иначе ваш код удалит старые подпредставления из существующей ячейки:

if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.textLabel.font = [UIFont boldSystemFontOfSize:12];
}
else {
    UIView* subview;
    while ((subview = [[[cell contentView] subviews] lastObject]) != nil)
      [subview removeFromSuperview];
}

альтернативный, более краткий способ достижения того же самого:

if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.textLabel.font = [UIFont boldSystemFontOfSize:12];
}
else {
    [[[cell contentView] subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
}
4 голосов
/ 22 декабря 2009

Это потому, что ячейка кэшируется, и вы продолжаете добавлять в представление содержимого, не удаляя то, что уже было добавлено.

Вы можете использовать более конкретный идентификатор ячейки и добавлять к представлению содержимого только при создании ячейки или очистить представление содержимого перед повторным добавлением меток.

Чтобы очистить подпредставления ячейки, вы можете добавить это:

if(cell == nil)
{...}
else
{
    UIView* subview;
    while ((subview = [[[cell contentView] subviews] lastObject]) != nil)
      [subview removeFromSuperview];
}

Когда ячейка! = Ноль, это означает, что это ячейка, в которой вы уже создали и добавили подвид, поэтому их необходимо очистить.

1 голос
/ 22 марта 2013

Не хотите автоматически выпускать UITableViewCell, потому что ваше приложение может аварийно завершить работу при многократной прокрутке и изменить положение устройства.

1 голос
/ 14 февраля 2012

Когда мы используем идентификатор повторного использования для UITableView, он понимает, что ячейка должна быть повторно использована, и значения в ячейках перезаписываются друг на друга, когда мы не указываем значения индекса идентификатора ячейки для повторного использования.

Нам нужно специально указать ячейку табличного представления, чтобы повторно использовать ячейку на пути индекса, т.е.

NSString *cellIdentifier = [NSString stringWithFormat:@"S%1dR%1d",indexPath.section,indexPath.row];

и использовать этот идентификатор ячейки в if (cell == nil)

UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellIdentifier:cellidentifier];

Это позволит устранить ошибочную связь между ячейками, и значения в ячейках не будут перезаписаны друг с другом. Более того, это позволяет избежать проблем связи между местоположениями индекса или значениями индекса ячейки. Надеюсь, это поможет, спасибо:) *

0 голосов
/ 21 июля 2016

Вы можете удалить подпредставление в другом состоянии, когда ячейка не равна нулю.

static NSString *CellIdentifier = @"CellIdentifier";        
UITableViewCell  *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    //create  a uitableviewcell
    if(cell == nil)
    {
     //Do whatever you want to do 

    }else{
        [[cell.contentView viewWithTag:YOUR_TAG] removeFromSuperview];
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...