Hi Guys, I'm trying to realize a UITableViewController with 7 sections. Each sections has a number of rows that could change by user events. For istance, in the first section I have a single row with a UISwitch: if the user activates the switch, 2 more rows appear in that section. The same for section 2. Ok for now.... In sections 3,4,5 I also have a single row (Value1 Cell, iPhone general settings like): by pressing on that cell, the sections shows on the 2nd row a UISegmented control with 3 segments. By pressing one of that segments, the user make his choice and the segmented control row disappears, the sections has a single row again with the value choosed as detailTextLabel.
Well, all these procedures are managed with a reloadSections method that reloads the sections in with the user is interacting. My code is below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [ tableView dequeueReusableCellWithIdentifier: CellIdentifier];
CellIdentifier = [ NSString stringWithFormat: @"%d:%d", [ indexPath indexAtPosition: 0 ], [ indexPath indexAtPosition:1 ]];
//cell = nil;
if(indexPath.section == 0 && [indexPath indexAtPosition: 1] == 0)
{
CellIdentifier = @"test";
}
if (cell == nil) {
cell = [ [ [ UITableViewCell alloc ] initWithFrame: CGRectZero reuseIdentifier: CellIdentifier] autorelease ];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
switch ([ indexPath indexAtPosition: 0]) {
case(0): {
switch([ indexPath indexAtPosition: 1]) {
case(0):
{
positionControl.tag = 0;
[positionControl addTarget:self action:@selector(toggleSwitch:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: positionControl ];
cell.textLabel.text = NSLocalizedString(@"Position",@"");
}
break;
case(1):
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = NSLocalizedString(@"Some Position",@"");
cell.detailTextLabel.text = NSLocalizedString(@"Last Known Position",@"");
}
break;
case(2):
{
cell.textLabel.text = NSLocalizedString(@"ReDo Position",@"");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
break;
}
}
break;
case(1): {
switch ([ indexPath indexAtPosition: 1 ]) {
case(0):
{
photoControl.tag = 1;
[photoControl addTarget:self action:@selector(toggleSwitch:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: photoControl ];
cell.textLabel.text = NSLocalizedString(@"photos",@"");
}
break;
case(1):
{
cell.textLabel.text = NSLocalizedString(@"Take photo",@"");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
break;
case(2):
{
cell.textLabel.text = NSLocalizedString(@"Select from Roll",@"");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
break;
}
}
break;
case(2): {
switch ([ indexPath indexAtPosition: 1 ]) {
case(0):
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = NSLocalizedString(@"size",@"");
if (UISegmentedControlNoSegment != [dimensionSegmentedControl selectedSegmentIndex]) {
cell.detailTextLabel.text = [dimensionSegmentedControl titleForSegmentAtIndex:[dimensionSegmentedControl selectedSegmentIndex]];
}
else {
cell.detailTextLabel.text = NSLocalizedString(@"Select",@"");
}
}
break;
case(1):
{
[dimensionSegmentedControl addTarget:self action:@selector(onSegmentedControlChanged:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:dimensionSegmentedControl];
}
break;
}
}
break; ...
Then my Action for switches:
- (IBAction) toggleSwitch: (id) sender {
UISwitch *switchControl = (UISwitch *) sender;
NSUInteger tag = switchControl.tag;
NSIndexSet *sectionsToReload = [[NSIndexSet alloc] initWithIndex:tag];
[self.tableView reloadSections:sectionsToReload withRowAnimation:NO];
[sectionsToReload release];}
Action for segmentedcontrol
- (IBAction) onSegmentedControlChanged: (id) sender {
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
NSUInteger tag = segmentedControl.tag;
NSIndexSet *sectionsToReload = [[NSIndexSet alloc] initWithIndex:tag];
segmentedControl.momentary = YES;
[self.tableView reloadSections:sectionsToReload withRowAnimation:NO];
segmentedControl.momentary = NO;
[sectionsToReload release];}
This is the didSelectRow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch ([ indexPath indexAtPosition: 0]) {
case(2): {
switch([ indexPath indexAtPosition: 1]) {
case (0): {
if (UISegmentedControlNoSegment != [dimensionSegmentedControl selectedSegmentIndex]) {
dimensionSegmentedControl.selectedSegmentIndex = [dimensionSegmentedControl selectedSegmentIndex];
}
else {
dimensionSegmentedControl.selectedSegmentIndex = 0;
}
NSIndexSet *sectionsToReload = [[NSIndexSet alloc] initWithIndex:2];
//[self.tableView reloadData];
[self.tableView reloadSections:sectionsToReload withRowAnimation:NO];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[sectionsToReload release];
}
break;
}
}
break;
case(3): {
switch([ indexPath indexAtPosition: 1]) {
case (0): {
if (UISegmentedControlNoSegment != [patientsSegmentedControl selectedSegmentIndex]) {
patientsSegmentedControl.selectedSegmentIndex = [patientsSegmentedControl selectedSegmentIndex];
}
else {
patientsSegmentedControl.selectedSegmentIndex = 0;
}
NSIndexSet *sectionsToReload = [[NSIndexSet alloc] initWithIndex:3];
//[self.tableView reloadData];
[self.tableView reloadSections:sectionsToReload withRowAnimation:NO];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[sectionsToReload release];
}
break;
default:
break;
}
}
break;
case(4): {
switch([ indexPath indexAtPosition: 1]) {
case (0): {
if (UISegmentedControlNoSegment != [patientsStateSegmentedControl selectedSegmentIndex]) {
patientsStateSegmentedControl.selectedSegmentIndex = [patientsStateSegmentedControl selectedSegmentIndex];
}
else {
patientsStateSegmentedControl.selectedSegmentIndex = 0;
}
NSIndexSet *sectionsToReload = [[NSIndexSet alloc] initWithIndex:4];
//[self.tableView reloadData];
[self.tableView reloadSections:sectionsToReload withRowAnimation:NO];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[sectionsToReload release];
}
break;
}
}
break;
case(5): {
switch([ indexPath indexAtPosition: 1]) {
case (0):
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://4030"]];
break;
case (1):
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://4030"]];
break;
}
}
break;
default: break;
}}
And finally my numbersOfRowsInSections, probably the problems source:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
switch (section) {
case (0):
{
if (!positionControl.on) {
return 1;
break;
}
return 3;
}
break;
case (1):
{
if (!photoControl.on) {
return 1;
break;
}
return 3;
}
break;
case (2):
{
if (UISegmentedControlNoSegment == [dimensionSegmentedControl selectedSegmentIndex] || [dimensionSegmentedControl isMomentary]) {
return 1;
break;
}
return 2;
}
break;
case (3):
{
if (UISegmentedControlNoSegment == [patientsSegmentedControl selectedSegmentIndex] || [patientsSegmentedControl isMomentary]) {
return 1;
break;
}
return 2;
}
break;
case (4):
{
if (UISegmentedControlNoSegment == [patientsStateSegmentedControl selectedSegmentIndex] || [patientsStateSegmentedControl isMomentary]) {
return 1;
break;
}
return 2;
}
break;
case (5): {
return 2;
}
break;
case (6): {
return 1;
}
break;
}
return 0;}
Well, now you can see my code, I'll explain my problem. When I deal with UISwitches, the sections reload properly....rows appear and disappear in the first two sections like a charm. But, when I click on the cells from sections with segmented controls, the first time everything is ok, the cell shows the segmented control, the user makes his choice, the segmented control disappears and the single row shows the user choice in the detailTextLabel.But when I try to click on another row, the app crashes with this exception:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 3. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted).' 2010-07-16 13:09:04.595 Barcodes[40421:207] Stack: ( 35943515, 2535093513, 36027451, 1928964, 4228395, 4172781, 278302, 4188742, 4171908, 1425834, 35728064, 35724360, 43226645, 43226842, 3915695, 86847, 86454 )
Difference between two sections is that ones with UISwitches show and hide rows by activating/deactivating the switch, others by selecting rows (didSelectRow....).
ANY HELP??
Thank you in advance.