Почему эта строка скрывает мой взгляд на стол? - cell = [self.tableView dequeueReusableCellWithIdentifier: CellIdentifier]; - PullRequest
0 голосов
/ 31 октября 2011

Когда я закомментирую эту строку в моей cellForRowAtIndexPath: функции:

cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

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

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

Короче, у меня есть UITableView, составленный из пользовательских UITableViewCell s. Пользовательские ячейки имеют следующее:

  • и UIStepper контроль
  • и id delegate для хранения вызывающего tableView, чтобы я мог запускать методы в tableView.
  • свойства, которые позволяют каждой ячейке хранить свой раздел и строку в табличном представлении

Постановка задачи:
Когда я загружаю tableview и пользователь касается элемента управления UIStepper в ячейке, он вызывает функцию делегата doit:, обратно в реализацию tableView. В этой функции свойства секции и строки пользовательской ячейки работают отлично, и они идеально указывают на правую секцию и строку в источнике данных (и tableView), но stepper.value устанавливается «как-то» на stepper.value из другая ячейка в таблице.

Кроме того, я действительно замечаю эту аномалию, только когда прокручиваю значительные расстояния в таблице ... т.е. сверху вниз. В нижней ячейке stepper.value будет ячейка, которая находилась рядом с верхней частью таблицы. Поэтому я думаю, что столкнулся с осложнением, связанным с кэшированием ячеек и т. Д.

Я включил код из класса customCell, а также из родительского TableView.

Кто-нибудь видит ошибку в моих способах? Большое спасибо.

Вот заголовочный файл customTableViewCell.

Возвращаясь к реальному TableView, где я создаю пользовательские ячейки, я вызываю метод setDelegate: пользовательской ячейки (показан ниже), чтобы понять, какая ячейка в таблице была нажата.

«Звездой» шоу является элемент управления UIStepper, который позволяет пользователю «поднимать» или «опускать» значение оценки, которое также отображается в ячейке.

#import <UIKit/UIKit.h>

@interface tvcCustomCellWithSetter : UITableViewCell {
    id delegate;
    NSNumber * row;
    NSNumber * section;
    int      originalValueIsSet; }

@property (nonatomic, assign) IBOutlet UILabel *score; @property
(nonatomic, assign) IBOutlet UILabel *catAndWeight; @property
(nonatomic, assign) IBOutlet UILabel *orgValueText; @property
(nonatomic, assign) IBOutlet UILabel *orgValueValue; @property
(nonatomic, assign) IBOutlet UIStepper *theStepper; @property
(nonatomic, assign) id delegate; @property (nonatomic, assign)
NSNumber *row; @property (nonatomic, assign) NSNumber *section;
@property (nonatomic, assign) int originalValueIsSet;

- (IBAction) bumpTheScore;
- (id)delegate;
- (void)setDelegate:(id)newDelegate;

@end

Вот важная часть файла customTableViewCell .m:

//
// here is my IBACTION function associated with a touch event on the UISetter control
//
-(void) bumpTheScore {

    [self.delegate doit:self];

}


- (id)delegate {
    return delegate;
}

// 
// this function is called when the cell is alloc'd over in the Tableview controller.
// it allows this custom cell to maintain a reference to the 
- (void)setDelegate:(id)newDelegate {
    delegate = newDelegate;
}

Вот TableView, в котором находятся объекты customViewCell.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    tvcCustomCellWithSetter *cell = nil;

    cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"customCell" owner:self options:nil];
        for(id currentObject in topLevelObjects){
            if([currentObject isKindOfClass:[tvcCustomCellWithSetter class]]) {
                cell = (tvcCustomCellWithSetter *)currentObject;
                break;
            }
        }


    } 

    // since the cell is a custom cell and it lives in a new class file, when events 
    // occur from toys in that cell (i.e. sliders, stepper, etc), the events go to that
    // class file.  I want those events to go to the simgrades class and run a reactive
    // function in there.  this is how you do that.   see the two functions in the 
    // custom class that work with this line.
    [cell setDelegate:self];

    // similarly, save the current section and row into the custom cell itself
    // so that later, when the stepper is clicked on one of the cells, we'll be able
    // to know the location in the datasource that is being addressed by the user.
    [cell setRow: [NSNumber numberWithInt: indexPath.row]];
    [cell setSection: [NSNumber numberWithInt: indexPath.section]];      

    // Set up the cell...
    [self.tableView setAllowsSelectionDuringEditing:NO];
    SimCat *tmpCat = [simCatalog objectAtIndex: indexPath.section];
    SimGrade *tmpGrd = [[tmpCat simGrades] objectAtIndex:indexPath.row];

    float averageScore, _score, _total;
    _score = [tmpGrd.scoreValue floatValue];
    _total = [tmpGrd.scorePossible floatValue];
    averageScore = (_score / _total) * 100;

    // Configure the cell...  Category name and description
    if (tmpGrd.isSimGrade) {
        cell.score.text = [NSString stringWithFormat:@"SimGrade: %2.2f%% - (%@ of %@)", averageScore, [tmpGrd.scoreValue stringValue] , [tmpGrd.scorePossible stringValue]];
        //for simulation grades, null out the orgValue labels.
        cell.orgValueValue.text = [NSString stringWithString: @""];
        cell.orgValueText.text = [NSString stringWithString: @""];
    } else {
        cell.score.text = [NSString stringWithFormat:@"Actual: %2.2f%% - (%@ of %@)", averageScore, [tmpGrd.scoreValue stringValue] , [tmpGrd.scorePossible stringValue]];
        //set the orig value label and turn on the boolean that shows that you've set this already.
        if (! cell.originalValueIsSet ) {
            cell.orgValueValue.text = [NSString stringWithFormat:@"%@", [tmpGrd.scoreValue stringValue]];
            cell.orgValueText.text = [NSString stringWithString: @"Original Value:"];
            cell.originalValueIsSet = true;
        }
    }

    cell.catAndWeight.text = [NSString stringWithFormat:@"Category: %@, Wt: %d", tmpCat.catName, [[tmpCat catWeight] intValue]];

    [cell.theStepper setValue:[tmpGrd.scoreValue floatValue]];
    [cell.theStepper setMaximumValue:[tmpGrd.scorePossible floatValue]];
    [cell.theStepper setMinimumValue:0];

    return cell;
}

Вот где у меня проблема. См. Описание проблемы в приведенном ниже коде.

- (void) doit: (id) sender {

    NSLog(@"it worked - i got back inside the tableview that houses the custom cells");
    NSLog(@"the user touched the UISetter control on a cell in section: %d", [[(tvcCustomCellWithSetter *)sender section] intValue]);
    NSLog(@"and that cell was in row: %d of that section", [[(tvcCustomCellWithSetter *)sender row] intValue]);

    // find the right section and row in the tableview's data source
    // point to the section indicated by the "section" passed in from the custom cell.
    SimCat *cat = [simCatalog objectAtIndex:[[(tvcCustomCellWithSetter *)sender section] intValue] ];

    // now point at the array item that corresponds to the "row" passed in from the custom cell
    SimGrade *grade = [[cat simGrades] objectAtIndex:[[(tvcCustomCellWithSetter *)sender row] intValue]];

    // now that we are pointing at the right array item in the tableview's datasource, update it's value to that of the UIStepper
    // control's value.
    // THE PROBLEM OCCURS IN THE FOLLOWING LINES.  The before value that is printed out is perfect.  So I know I am able to 
    // reference the correct value in the datasource that the user has just incremented or decremented with the UIStepper
    // control.  The "theStepper.value" should contain a number that is one more or one less than the previous value...
    // HOWEVER, the value stored in theStepper.value is actually a value from one of the other cells in the table.
    // I'm thinking that this has to do with the way the table cells are cached.  I usually see this error when I scroll to the
    // bottom of the tableview.  

    NSLog(@"before: %f", [[grade scoreValue] floatValue]);
    grade.scoreValue = [NSNumber numberWithFloat: [[(tvcCustomCellWithSetter *)sender theStepper] value]];
    NSLog(@"after: %f", [[grade scoreValue] floatValue]);

    // you have changed some values in the Tableview's datasource so you should repaint the view.
    [self loadHTMLHeader];
    [[self tableView] reloadData];

    return;
}

Ответы [ 2 ]

0 голосов
/ 01 ноября 2011

В итоге я решил эту проблему, ударившись головой о стену и разделив класс UIStepper на подклассы, чтобы добавить свойство строки и раздела, которое позволило мне определить, какая ячейка табличного представления представляла элемент управления при нажатии на него.Я также использовал метод setTarget, помещаемый в каждую ячейку во время метода cellforrowatindexpath (), он вызывал бы функцию в моем классе табличного представления всякий раз, когда значение изменялось в UIStepper.В этой функции я смог использовать значения строк и разделов из customStepper, чтобы точно определить строку в таблице и, следовательно, источник данных, который необходимо обновить.

Whew.

0 голосов
/ 31 октября 2011

Чтобы предотвратить перенос значений theStepper, вам необходимо явно установить для них значение по умолчанию, если ваш метод dequeueReusableCell.. возвращает ячейку.

Итак:

cell = (tvcCustomCellWithSetter *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {
    NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"customCell" owner:self options:nil];
    for(id currentObject in topLevelObjects){
        if([currentObject isKindOfClass:[tvcCustomCellWithSetter class]]) {
            cell = (tvcCustomCellWithSetter *)currentObject;
            break;
        }
    }
} else {
    cell.theStepper.value = 0;
    cell.theStepper.maximumValue = 1;
    // cell.theStepper.minimumValue = 0; this should already be set properly
}

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

РЕДАКТИРОВАТЬ: Я буду более конкретным.После отладки вы увидите, как шагаете по коду:

  • Для значений шага явно заданы значения по умолчанию перед установкой правильного значения, или
  • Значения не являютсяявно установлено по умолчанию (что означает, что ваш код сброса значения не работает).

А затем:

  • Значение шага установлено на правильное значение для текущегоячейка, или
  • Шаговое значение установлено на значение, отличное от ожидаемого (в этом случае вам необходимо проследить код в точке, где он устанавливает это значение, и посмотреть, что это за индексы и какое значениеон выбирает и т. д.), ИЛИ
  • Значение шага вообще не изменилось по сравнению с его значением по умолчанию (это означает, что код для установки падает или есть необычный случай, когда вы получаете nil, 0 или просто не выполняется код для установки значения, и вам нужно проследить и увидеть, куда код попадает на этот этап).

Это должен быть ваш стандартный debпроцедура извлечения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...