8

I have a table view with 4 sections and 1-2 table view cells per section. The first cell has a uiswitch as an accessory view and controls the color theme of the app, switching between day mode and night mode. Once the switch is hit a function is called, changing the colors of the nav bar and background color. In that function I've also put the line

[self.tableview reloadData];

to update the table itself with the new colors. It works fine but theres no animation to it, so I used this instead

[self.tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 3)] withRowAnimation:UITableViewRowAnimationFade];

When that line is used the switch gets stuck and the app freezes. It doesn't crash per say, i.e. there is no crash log, it just freezes and the uiswitch stops mid animation.

I noticed that i can reload sections which don't have cells that contain accessory views and it works perfectly with the fade animation. I.e. this works

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationFade];

Because the third section does not have any cells with accessory views. But any section that has a cell that contains an accessory view (i.e. sections 0 and 2) if I try and reload it the app freezes.

Any ideas why this is happening? Below is my cellForRowAtIndexPath

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

static NSString *cellIdentifier;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];

if (indexPath.section == 0) {

    cell.textLabel.text = [section0 objectAtIndex:indexPath.row];
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    if (indexPath.row == 0) {

        cell.accessoryView = colorSchemeSwitch;
    }

    else if (indexPath.row == 1) {

        cell.accessoryView = autoLockSwitch;
    }
}

else if (indexPath.section == 1) {

    cell.textLabel.text = [section1 objectAtIndex:indexPath.row];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}

else if (indexPath.section == 2) {

    cell.textLabel.text = [section2 objectAtIndex:indexPath.row];
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%i \t", (int)app.fontSize];
    fontSizeSlider.value = app.fontSize;
    cell.accessoryView = fontSizeSlider;
}

else if (indexPath.section == 3) {

    cell.textLabel.text = [section3 objectAtIndex:indexPath.row];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    cell.detailTextLabel.text = app.color;
}

cell.backgroundColor = app.cellBackgroundColor;
cell.textLabel.textColor = app.textColor;
UIView *backgroundColorView = [[UIView alloc] init];
backgroundColorView.backgroundColor = app.cellSelectedColor;
[cell setSelectedBackgroundView:backgroundColorView];

return cell;
}
jcooper_82
  • 97
  • 1
  • 1
  • 8

3 Answers3

9

I had the same issue in UITableViewCell comprising UISwitch. I solved the problem by calling [self.tableview reloadData] before reloading the sections:

NSIndexSet *sections = [[NSIndexSet alloc] initWithIndex:2];
[self.tableView reloadData];
[self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationFade];

The same problem happens if you call:

[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationFade]

without reloading the data first.

pjuzeliunas
  • 1,596
  • 1
  • 15
  • 19
  • Your are a legend! That worked perfectly. Can't believe it was this simple – jcooper_82 Mar 14 '15 at 01:38
  • 21
    If we are calling reload table then why reloading section is needed for animation ? (H) – dip Aug 05 '15 at 10:04
  • 8
    I agree with @dip, either "reloadData" or "reloadSections" should be called, but not both. With that said, I randomly get a SIGABRT crash with using just "reloadSections" between "beingUpdates" and "endUpdates". I am still trying to figure out why... – jjmias Dec 23 '15 at 17:41
  • 7
    I agree with the above comments. Either use reloadData or reloadSections, both does not make sense – zirinisp Jul 24 '16 at 09:28
  • 1
    I believe you need to call reloadData at least once - in order for the numberOfSections delegate function to be called. Then you can call reloadSection as needed (and while your number of sections is not changing). – GK100 Jun 26 '17 at 15:14
  • why call reloadSections if you solve calling reload of entire table by reloadData ? – doxsi Sep 29 '17 at 10:39
  • You should check out the solution here (add and removing the sections in an updates block) https://stackoverflow.com/a/13010576/1433553 – atlex2 Aug 28 '18 at 16:40
  • Does this crash is iOS versions specific? , Seems like not getting the crash on iOS 10 and above but only getting on iOS 9. – Sagar Daundkar Sep 06 '18 at 05:09
  • If you have already called tableview.reload() no need to reload sections again. – Arshad Shaik Jun 20 '23 at 10:09
5

you haven't added a crash log but im guessing you are getting an error that states an existing number of rows in a section must be equal to some value before an update. If that's the case, Did you use [self.tableview beginUpdates] before reloading the table and [self.tableview endUpdates] after reloading?

Frantz Romain
  • 836
  • 1
  • 6
  • 14
0

I was getting the same issue, when trying to reload a specific row. there was a inconsistency in my dataSource. because i was loading data from remote. I found this link which solved the problem. But i needed to modify this line.

let sections = dataSource.numberOfSections?(in: self) ?? 0

To

let sections = dataSource.numberOfSections?(in: self) ?? 1

Abdul Momen
  • 379
  • 2
  • 13