Cocoa-Touch - UITableView dequeueReusableCellWithIdentifier给了我错误的单元格数据

时间:2012-01-19 15:00:01

标签: objective-c ios cocoa-touch uitableview

我正在尝试在UITextField中使用UITableViewCell,如下面的代码所示。似乎当tableview离开屏幕时,应该在单元格中的一些数据被混淆。我认为方法[tableView dequeueReusableCellWithIdentifier:addGroupContactCellIdentifier];在tableview离开屏幕后无法给我一个“正确”的单元格时会出现一些问题。这是什么原因?

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

    static NSString *addGroupContactCellIdentifier = @"AddGroupContactCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:addGroupContactCellIdentifier];

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                       reuseIdentifier:addGroupContactCellIdentifier];

        if ([indexPath section] == 0) { // Group Name Section

            cell.textLabel.text = @"Name";

            UITextField *groupNameTextField = [[UITextField alloc]initWithFrame:CGRectMake(80, 10, 210, 22)];
            groupNameTextField.textAlignment = UITextAlignmentLeft;
            groupNameTextField.backgroundColor = [UIColor clearColor];
            groupNameTextField.placeholder = @"Type Group Name";

            //groupNameTextField.borderStyle = UITextBorderStyleLine;
            groupNameTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
            groupNameTextField.returnKeyType = UIReturnKeyDone;
            groupNameTextField.autocapitalizationType = UITextAutocapitalizationTypeSentences;
            groupNameTextField.delegate = self;

            [cell.contentView addSubview:groupNameTextField];

        }

    }

    if ([indexPath section] == 1) { // Contacts Section

        cell.textLabel.text = [[self.selectedPeoplePickerContacts objectAtIndex:[indexPath row]] objectForKey:@"name"];
        cell.detailTextLabel.text = [[self.selectedPeoplePickerContacts objectAtIndex:[indexPath row]] objectForKey:@"number"];

    }

    cell.accessoryType = UITableViewCellAccessoryNone;

    return cell;    
}

更新

所以我将UITableViewCell子类化了,但它仍然表现出与以前相同的错误。这是我tableView:cellForRowAtIndexPath:的代码:

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

    static NSString *addGroupContactCellIdentifier = @"AddGroupContactCell";

    if ([indexPath section] == 0) {

        UITableViewCellWithUITextField *cell = [tableView dequeueReusableCellWithIdentifier:addGroupContactCellIdentifier];

        if (cell == nil) {

            //cell = [[UITableViewCellWithUITextField alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:addGroupContactCellIdentifier];

            cell = [[UITableViewCellWithUITextField alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:addGroupContactCellIdentifier textFieldPlaceholder:@"Type Group Name" textFieldDelegate:self];
        }

        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.textLabel.text = @"Name";

        // Need to set the UITableViewCell's textLabel properties otherwise they will cover the UITextField
        cell.textLabel.opaque = NO;
        cell.textLabel.backgroundColor = [UIColor clearColor];

        return cell;

    } else { 

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:addGroupContactCellIdentifier];

        if (cell == nil) {

            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                          reuseIdentifier:addGroupContactCellIdentifier];
        }

        cell.textLabel.text = [[self.selectedPeoplePickerContacts objectAtIndex:[indexPath row]] objectForKey:@"name"];
        cell.detailTextLabel.text = [[self.selectedPeoplePickerContacts objectAtIndex:[indexPath row]] objectForKey:@"number"];

        return cell;
    }
}

第三次编辑(我现在有2个不同的reuseIdentifiers,似乎给了我想要的结果):

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

    if ([indexPath section] == 0) { // Group Name Section

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

        if (cell == nil) {

            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                          reuseIdentifier:groupNameCellIdentifier];

            cell.textLabel.text = @"Name";

            UITextField *groupNameTextField = [[UITextField alloc]initWithFrame:CGRectMake(80, 10, 210, 22)];
            groupNameTextField.textAlignment = UITextAlignmentLeft;
            groupNameTextField.backgroundColor = [UIColor clearColor];
            groupNameTextField.placeholder = @"Type Group Name";

            //groupNameTextField.borderStyle = UITextBorderStyleLine;
            groupNameTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
            groupNameTextField.returnKeyType = UIReturnKeyDone;
            groupNameTextField.autocapitalizationType = UITextAutocapitalizationTypeSentences;
            groupNameTextField.delegate = self;

            [cell.contentView addSubview:groupNameTextField];
        }

        // Customization


        return cell;

    } else {

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

        if (cell == nil) {

            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                          reuseIdentifier:addGroupContactCellIdentifier];
        }

        // Customization
        cell.textLabel.text = [[self.selectedPeoplePickerContacts objectAtIndex:[indexPath row]] objectForKey:@"name"];
        cell.detailTextLabel.text = [[self.selectedPeoplePickerContacts objectAtIndex:[indexPath row]] objectForKey:@"number"];

        return cell;
    }
}

3 个答案:

答案 0 :(得分:1)

有些人建议不要进行子类化。

但你不能使用“if([indexPath section] == 0){”在“if(cell == nil){”之内的逻辑,因为这只是第一次创建单元格时调用它,它将在其他指数中用于后续的回收。

相反,您需要使用两个不同的CellIdentifier,以便为零部分设置的单元格不会在表中的其他位置重复使用。在将单元格出列之前,将if([indexPath section] == 0){放在第0部分和后续的单元格中使用不同的单元格标识符。

另外,请确保在“if(cell == nil){”之外执行任何特定于索引路径的操作,以便每次重复使用单元格时都会应用它,而不仅仅是第一次创建单元格时。< / p>

答案 1 :(得分:0)

你是对的!问题肯定是由于reusability的{​​{1}}功能造成的。 Apple已经完成了这样的工作,以便您可以重复使用单元格,并且它在性能方面的表现非常出色!因此,当您尝试向上和向下滚动时,UITableView值仍然相同,而您的tableView会从您在班级中定义的indexPath获取数据!

<强>解决方案:

您需要继承cellForRowAtIndexPath并在UITableViewCell方法中添加UITextField

然后,您需要引用此-(void)layoutSubviews并使用它来加载TableView。

有助于: Read this !

的链接

答案 2 :(得分:0)

值混淆了,因为当你离开屏幕然后再次重新加载表格时,单元格会从内部表格单元格池中被取消,但它们的重新加载方式与之前表格中的顺序不同。请注意,即使您有一个包含许多行的表并滚动它,也会发生这种混合。解决方案是将文本字段数据存储在“数据源”数组中,然后配置单元格。

说明

基本上在您的代码中存在一个主要的概念缺陷:一旦重新生成了单元格,就不能正确配置内容(根本不配置它)。我的意思是,最初,当第一次显示表时,池是空的。因此,需要显示的每个新单元都是从头开始重新创建的(不是从池中取出);假设您的表格可以在屏幕上显示10个单元格,因此前10个单元格将全部从头开始创建,包含空文本字段。 然后你开始在这些字段中输入文本,一切正常。 在某一时刻,您开始滚动单元格:会发生的是,顶部的所有单元格将从屏幕中消失并存储(排队)在表池中,包含其文本字段及其编辑内容;假设您在第0行排队单元格。当需要在屏幕底部显示新单元格时,您的代码所做的第一件事就是尝试对单元格进行双击。现在这次你在池中有一个单元格(第0行的单元格),这个单元格从池中检索出来并放在表格中,包括第11行的TEXTFIELD内容。所以“神奇地”你会发现一个在另一行的第0行编辑的文本,11。此外,从池中以稀疏顺序检索单元格,因此在经过多次文本字段编辑和滚动后,您将完全混淆。

解决方案,这就是代码中出现错误的原因:只要创建或取消了单元格,就配置它,即设置文本字段内容。如何检索文本字段内容?存储在一个数组中。这就是您的视图控制器是“数据源”的原因,因为您可以使用数据来填充表格。由于这种去队列机制,将数据存储在表中是一个错误。例如:


groupNameTextField.text=[myTextFieldContentArray objectAtIndex:indexPath.row];

另一个解决方案,但我不建议,是为每个单元格分配一个唯一的标识符,即:


NSString *myCellId = [NSString stringWithFormat:@"CellID_%d_%d",indexPath.section,indexPath.row];

在这种情况下,所有单元格都将使用不同的名称,您永远不会混淆它们。 这个解决方案大部分时间都在工作,但由于两个原因而不鼓励: 一个。它不是最优的,因为你不重复使用单元格,因此这会占用类似单元格的额外内存 湾你无法保证每个单元都有效地排队,所有这些逻辑都在表内,并且它不会暴露给开发人员,因此可能需要在每次需要时重新生成单元(性能损失)