UITableView с двумя типами повторно используемых ячеек не работает должным образом - PullRequest
1 голос
/ 14 декабря 2011

Я пытаюсь создать табличное представление, которое использует два типа ячеек - по умолчанию и субтитры.

Я пытался использовать одну повторно используемую ячейку (*cell), которая, казалось, работала нормально, пока я не добрался до нижней ячейки, которая была за кадром - когда это появилось, это была копия первой видимой ячейки,

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

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'

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

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

Заранее спасибо.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
 return 1;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return  5; 
}

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

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

 UITableViewCell *cellB = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCellB"];


switch (indexPath.section) {


 case 0:
     if (cell == nil) {
         // The only subtitle cell
         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle
                                      reuseIdentifier:@"UITableViewCell"]; 

     }

        [[cell textLabel] setText:title];
        [[cell textLabel] setTextColor:[UIColor whiteColor]]; 
        [[cell detailTextLabel] setText:[NSString stringWithFormat:@"Entry: £%@",price]];
        [[cell detailTextLabel] setTextColor:[UIColor colorWithWhite:1.0 alpha:.8]]; 


        cell.selectionStyle = UITableViewCellSelectionStyleNone; 

     break;

 case 1:
     if (cell == nil) {

         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:@"UITableViewCell"]; 

         UIView *cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
         cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PhotoFrame.png"]];
         cell.backgroundView = cellBackView;

     }

     [lImage setFrame:CGRectMake(0, 23, 320, 200)];

     [cell.contentView addSubview:lImage];

     break;

 case 2:
     if (cell == nil) {

         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:@"UITableViewCell"]; 

         UIView *cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
         cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PaperTop.png"]];
         cell.backgroundView = cellBackView;

     }

     break;

 case 3:
     if (cell == nil) {

         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:@"UITableViewCell"]; 


         UIView *cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
         cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"Paper.png"]];
         cell.backgroundView = cellBackView;

     }

     break;

 case 4:
     // I'm pretty sure this bit is wrong but if I use (cell == nil) the first cell is shown instead
     if (cellB == nil) {

         cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:@"UITableViewCellB"]; 

         UIView *cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
         cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PaperBottom.png"]];
         cell.backgroundView = cellBackView;

     }

     break;

 default:
     break;
} 

 return cell; 
}

Ответы [ 4 ]

2 голосов
/ 14 декабря 2011

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

Итак, сначала вы хотите удалить одну ячейку из очереди каждый раз, когда вызывается этот метод.Отменяя ячейки типа UITableViewCell' and UITableViewCellB ', вы удаляете ячейку, которая не будет использоваться.Таким образом, вам нужно определить, какой тип ячейки вам нужен, прежде чем снимать ее с очереди, а затем снять ее с нужного типа (по идентификатору повторного использования).

Во-вторых, цель механизма очередей ячеек состоит в том, чтобы вы не делали этого.приходится делать такие вещи, как настраивать внешний вид ячейки каждый раз, когда она появляется в представлении.Если ячейка с таким типом появления уже находится в очереди, она должна выйти из уже настроенной очереди, и вам нужно только поместить в нее данные.Это сделано для производительности (скорости), но это может не иметь большого значения в вашем случае.

Возможно, я ошибаюсь, и я исправлю свой ответ, если это так, но сообщение об ошибке может быть связано с тем, что число разделов, возвращаемых numberOfSections, и / или число или строки, возвращаемые numberOfRowsInSection: неверно и не соответствует источнику данных.Он пытается получить доступ к элементу источника данных, который не существует.

Какой источник данных вы используете, и можете ли вы показать код для numberOfSections и numberOfRowsInSection:?

ОБНОВЛЕНИЕ с исправлением

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

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

UIView *cellBackView;  // move this outside of the switch block

switch (indexPath.section) {


 case 0:

   [[cell textLabel] setText:title];
   [[cell textLabel] setTextColor:[UIColor whiteColor]]; 
   [[cell detailTextLabel] setText:[NSString stringWithFormat:@"Entry: £%@",price]];
   [[cell detailTextLabel] setTextColor:[UIColor colorWithWhite:1.0 alpha:.8]]; 
   cell.selectionStyle = UITableViewCellSelectionStyleNone; 
   break;

 case 1:

    cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
    cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PhotoFrame.png"]];
    cell.backgroundView = cellBackView;
    [lImage setFrame:CGRectMake(0, 23, 320, 200)];
    [cell.contentView addSubview:lImage];
    break;

 case 2:

    cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
    cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PaperTop.png"]];
    cell.backgroundView = cellBackView;
    break;

 case 3:

    cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
    cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"Paper.png"]];
    cell.backgroundView = cellBackView;
    break;

 case 4:
    cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
    cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PaperBottom.png"]];
    cell.backgroundView = cellBackView;
    break;

 default:
    break;
} 

 return cell; 
}
2 голосов
/ 14 декабря 2011

Если cellB не ноль, вы все равно возвращаете cell, а не cellB.

Редактировать:

Чтобы исправить, добавьтекод в блоке case 4 выглядит следующим образом:

case 4:
    if (cellB == nil) {
        // No changes in here
    }
    else {             //
        cell = cellB;  // Add these 3 lines
    }                  //
    break;
0 голосов
/ 14 декабря 2011

Как указывал cgull, когда [indexPath section] равен 4, вы инициализируете cellB, но по-прежнему возвращаете cell, в котором может быть или не быть действительной ячейки.

У вас должна быть одна переменная, которая содержит ячейку, которую вы собираетесь вернуть, независимо от пути, пройденного через switch:

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

    NSString identifier = @"UITableViewCell";
    if( [indexPath section] == 4 ){
        identifier = @"UITableViewCellB";
    }
    // Try to dequeue the appropriate cell kind
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];


    switch (indexPath.section) {

            //other cases...

        case 4:
            // You now have only one variable that can possibly hold a cell.
            // If section is 4, it's either nil or a UITableViewCellB kind.
            if (cell == nil) {

                cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:@"UITableViewCellB"];
                // Set up new cell

            }

            break;

        default:
            break;
    } 

    return cell; 
}
0 голосов
/ 14 декабря 2011

cgull правильно. Заменить случай 4 следующим:

case 4:
  if (cellB == nil) {

     // assign to the correct cell
     cellB = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:@"UITableViewCellB"]; 

     UIView *cellBackView = [[UIView alloc] initWithFrame:CGRectZero];
     cellBackView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:@"PaperBottom.png"]];
     cell.backgroundView = cellBackView;

 }

 return cellB;  // <--- return the correct cell
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...