[英]UITableView cells containing a UISwitch update inconsistently
I have a UITableView
where each cell contains a UISwitch
. 我有一个
UITableView
,其中每个单元格包含一个UISwitch
。 The switch is supposed to toggle the content named in the cell as active or not, and it works perfectly when the user toggles the switch. 该开关应该切换单元格中命名为活动的内容或不激活的内容,并且当用户切换该开关时,它可以完美地工作。
However, then I got the bright idea of also doing the toggling when the entire table row is selected. 但是,然后我想到了一个聪明的主意,即在选择整个表行时也进行切换。 Simple in theory right?
理论上简单吧? And it was, in terms of updating the data model.
而且,就更新数据模型而言。
However, for whatever reason that has had me stumped for the last 2 hours, only the switch in cell #3 updates to reflect the state change when I reload the table data. 但是,无论出于什么原因使我在过去2个小时内都感到困惑,重新加载表数据时,只有单元格3中的开关才会更新以反映状态更改。 No matter how many rows I have in the table, it is always only the third cell that works.
无论表中有多少行,始终只有第三个单元起作用。 If there are less than 3 cells, then no cells work.
如果少于3个单元,则没有单元起作用。
I've dumped a load of NSLog
calls in there and they reflect the proper data states as I'd expect at all times, but they just aren't being reflected in the switch beyond the first load. 我在其中转储了一个
NSLog
调用负载,它们始终反映出我所希望的正确数据状态,但是它们并没有反映在第一次加载之后的切换中。 If I leave the view controller then come back, the switches are all properly set... 如果我离开视图控制器然后回来,则所有开关都已正确设置...
I just know this is going to be some stupid thing I've done somewhere, because it works in exactly one instance, but for the life of me I cannot see it :( 我只是知道这将是我在某处所做的一些愚蠢的事情,因为它仅在一个实例中起作用,但是对于我一生,我看不到它:(
Can you? 你是否可以?
-(void)viewDidLoad
{
[super viewDidLoad];
[_tableAddPeople setDelegate:self];
[_tableAddPeople setDataSource:self];
}
-(void)viewWillAppear:(BOOL)animated
{
[_tableAddPeople reloadData];
}
-(void)listSwitchChanged:(id)sender
{
UISwitch * switchControl = sender;
Person * person = [SAVE_DATA getPersonWithIndex:(int)switchControl.tag];
if (switchControl.on)
{
[SAVE_DATA activePeopleAdd:person.tag];
}
else
{
[SAVE_DATA activePeopleRemove:person.tag];
}
}
#pragma mark UITableViewDataSource Delegate
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [SAVE_DATA peopleCount];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * cell = [_tableAddPeople dequeueReusableCellWithIdentifier:@"AddPeopleCell"];
UILabel * nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
UISwitch * activeSwitch = (UISwitch *)[cell.contentView viewWithTag:2];
Person * person = [SAVE_DATA getPersonWithIndex:(int)[indexPath row]];
[nameLabel setText:[person name]];
BOOL active = [SAVE_DATA activePeopleContains:person.tag];
NSLog(@"Row for %@ is %@", person.name, (active? @"ON" : @"OFF"));
[activeSwitch setOn:active animated:YES];
[activeSwitch addTarget:self action:@selector(listSwitchChanged:) forControlEvents:UIControlEventValueChanged];
activeSwitch.tag = (int)[indexPath row];
return cell;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
#pragma mark UITableView Delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Person * person = [SAVE_DATA getPersonWithIndex:(int)[indexPath row]];
if ([SAVE_DATA activePeopleContains:person.tag])
{
NSLog(@"Removing %@", person.name);
[SAVE_DATA activePeopleRemove:person.tag];
}
else
{
NSLog(@"Adding %@", person.name);
[SAVE_DATA activePeopleAdd:person.tag];
}
[_tableAddPeople reloadData];
//dispatch_async(dispatch_get_main_queue(), ^{[tableView reloadData];});
}
Your problem is that you are using the switch tag
property for two things: 您的问题是您将switch
tag
属性用于两件事:
Because you are assigning indexPath.row
to tag
, in the case where the index path isn't 2 (ie the third row), [cell.contentView viewWithTag:2];
因为您是将
indexPath.row
分配给tag
,所以在索引路径不是2(即第三行)的情况下, [cell.contentView viewWithTag:2];
will return nil
when the cell is re-used. 重用该单元格时将返回
nil
。
You also have an issue with cell re-use because you are adding the switch action handler multiple times. 您还存在单元重用的问题,因为您要多次添加switch操作处理程序。
I would suggest that you adopt the following approach: 我建议您采用以下方法:
Expose your cell's sub views using properties and cast the result of dequeueReusableCell
to your UITableViewCell
subclass so that you can access them without needing to use the tag 使用属性公开单元的子视图,并将
dequeueReusableCell
的结果dequeueReusableCell
为UITableViewCell
子类,以便无需使用标签即可访问它们
Establish your UITableViewCell
subclass as the switch action handler. 建立
UITableViewCell
子类作为切换操作处理程序。
Implement a delegation pattern between the cell and your view controller, so that the cell can notify the view controller that the switch changed. 在单元格和视图控制器之间实现委派模式,以便单元格可以通知视图控制器该开关已更改。 The cell can pass
self
to the delegate method. 单元格可以将
self
传递给委托方法。 In the delegate method you can use indexPathForCell
to determine the affected row. 在委托方法中,可以使用
indexPathForCell
确定受影响的行。
Don't reload the whole tableview just because one row has changed. 不要仅因为一行已更改而重新加载整个tableview。 Only reload the affected row.
仅重新加载受影响的行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.