Objective c 可可触感&x2013;UITableView dequeueReusableCellWithIdentifier为我提供了错误的单元格数据
我试图在Objective c 可可触感&x2013;UITableView dequeueReusableCellWithIdentifier为我提供了错误的单元格数据,objective-c,ios,cocoa-touch,uitableview,Objective C,Ios,Cocoa Touch,Uitableview,我试图在UITableViewCell中使用UITextField,如下面的代码所示。似乎当tableview离开屏幕时,单元格中应该包含的一些数据被混淆了。我认为方法[tableView dequeueReusableCellWithIdentifier:addGroupContactCellIdentifier]存在一些问题在tableview离开屏幕后无法给我一个“正确”的单元格。这是什么原因 - (UITableViewCell *)tableView:(UITableView *)ta
UITableViewCell
中使用UITextField
,如下面的代码所示。似乎当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:(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;
}
}
因此,我将UITableViewCell
子类化,但它仍然显示出与以前相同的错误。这是我的tableView:cellforrowatinexpath:
的代码:
- (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;
}
}
第三次编辑(我现在有两个不同的重用标识符,它们似乎给了我想要的结果):
- (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;
}
}
你说得对!这个问题肯定是由于UITableView
的可重用性
特性造成的。苹果以这样的方式做到了这一点,这样你就可以重复使用电池了,而且从性能的角度来看,它工作得非常出色!因此,当您尝试上下滚动时,indepath
值仍然相同,并且tableView从类中定义的cellforrowatinexpath
获取数据
解决方案:
- (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;
}
}
您需要对UITableViewCell
进行子类化,并在-(void)layoutSubview
方法中添加UITextField
然后,您需要引用此CustomUITableViewCell
,并使用它来加载TableView
一个有帮助的链接:这些值混合在一起,因为当您离开屏幕,然后再次重新加载表格时,这些单元格将从内部表格单元格池中删除,但它们不会按照以前在表格中的顺序重新加载。请注意,即使您有一个包含许多行的表并滚动它,也会发生这种混合。解决方案是将文本字段数据存储在“数据源”数组中,然后配置单元格
解释
基本上,代码中存在一个主要的概念缺陷:一旦重新生成单元格,就无法正确配置内容(根本无法配置)。我的意思是,最初,当第一次显示表时,池是空的。因此,需要显示的每个新单元格都会从头开始重新创建(而不是从池中删除);假设您的表可以在屏幕上显示10个单元格,那么前10个单元格将全部从头创建,并带有空文本字段。
然后开始在这些字段中输入文本,所有操作都正常。
在某一点上,您开始滚动单元格:发生的情况是,位于顶部的所有单元格将从屏幕上消失,并存储(排队)在表池中,以及它们的文本字段及其编辑的内容;假设您在第0行对单元格进行排队。当一个新的单元格需要显示在屏幕底部时,代码要做的第一件事就是尝试对单元格进行消隐。现在,这一次池中有一个单元格(第0行的单元格),该单元格将从池中检索并放置在表中,包括第11行的TEXTFIELD内容。所以“神奇地”你会在另一行11的第0行找到一个被编辑的文本。此外,单元格是以稀疏的顺序从池中检索的,因此在许多文本字段编辑和滚动之后,您将有一个完整的混合
解决方案,这就是代码中出现错误的原因:一旦创建或删除单元格,就对其进行配置,即设置textfield内容。如何检索文本字段内容?存储在数组中。这就是为什么视图控制器是一个“数据源”,因为您需要源数据来填充表。由于这种去队列机制,在表中存储数据是错误的。例如:
groupNameTextField.text=[myTextFieldContentArray objectAtIndex:indexPath.row];
另一个解决方案,但我不建议,是为每个单元格分配一个唯一的标识符,即:
NSString *myCellId = [NSString stringWithFormat:@"CellID_%d_%d",indexPath.section,indexPath.row];
在这种情况下,所有的细胞将被赋予不同的名称,你永远不会混淆它们。
此解决方案大部分时间都有效,但由于以下两个原因不鼓励使用:
A.这是非最优的,因为您不重用单元,所以这会为类似的单元占用额外的内存
B您不能保证每个单元都有效地排队,所有这些逻辑都在表中,并且不向开发人员公开,因此您可能需要在需要时每次重新生成单元(性能损失)。如一些人所建议的,不需要子类化
但是您不能在“if(cell==nil){”中使用类似“if([indepath section]==0){”这样的逻辑,因为它只在第一次创建单元时被调用,并且将在后续循环的其他索引中重新使用
相反,您需要使用两个不同的单元标识符,以便为第0节设置的单元不会在表中的其他位置重复使用。在将单元出列之前,请将if([indexPath section]==0){放入单元格,并为第0节和后续的节单元使用不同的单元标识符
此外,请确保在“if(cell==nil){”之外执行任何特定于indexpath的操作,以便在每次重复使用单元格时应用它,而不仅仅是在第一次创建单元格时应用它。我不是UITableViewCell的子类。但我见过其他处理它的方法(我假设没有问题)子类化是摆脱可重用性问题的唯一解决方案!!@PeterWarbo当然。没错!这将摆脱可重用性问题。但根据经验……我会再次选择子类化,因为从长远来看,这将帮助您解决问题!