Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - Loop through Cells and retrieve data

Sorry I'm pretty new to iOS dev.

I have a UITableView setup from cells being pulled from a single XiB nib. I've created a on/off switch in the nib, and I am trying to save the state of the switch upon viewWillDisappear for the number of cells that I have. (6 cells to be exact).

How can I loop through all the cells and save this information?

I tried this in my UIViewController to get the info for one cell:

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    UITableView *tv = (UITableView *)self.view;
    UITableViewCell *tvc = [tv cellForRowAtIndexPath:0];

}

it gives me the error "Program received signal: "EXC_BAD_INSTRUCTION".

How can I accomplish this?

like image 951
Romes Avatar asked Dec 17 '22 04:12

Romes


2 Answers

You have to pass a valid NSIndexPath to cellForRowAtIndexPath:. You used 0, which means no indexPath.

You should use something like this:

UITableViewCell *tvc = [tv cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];

BUT. Don't do this. Don't save state in the UITableViewCell.
Update your dataSource when a switch changed its state.

If you have implemented the UITableViewDataSource methods the right why your tableView reuses cells. That means the state of your cells will vanish when the cells are reused.

Your approach might work for 6 cells. But it will fail for 9 cells.
It will probably even fail if you scroll the first cell off screen.


I wrote a quick demo (if you don't use ARC add release where they are necessary) to show you how you should do it instead:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.dataSource = [NSMutableArray arrayWithCapacity:6];
    for (NSInteger i = 0; i < 6; i++) {
        [self.dataSource addObject:[NSNumber numberWithBool:YES]];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        UISwitch *aSwitch = [[UISwitch alloc] init];
        [aSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
        cell.accessoryView = aSwitch;
    }
    UISwitch *aSwitch = (UISwitch *)cell.accessoryView;
    aSwitch.on = [[self.dataSource objectAtIndex:indexPath.row] boolValue];
    /* configure cell */
    return cell;
}

- (IBAction)switchChanged:(UISwitch *)sender 
{
//    UITableViewCell *cell = (UITableViewCell *)[sender superview];
//    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    CGPoint senderOriginInTableView = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:senderOriginInTableView];
    [self.dataSource replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:sender.on]];
}

as you see it's not very complicated to not store state in the cells :-)

like image 164
Matthias Bauch Avatar answered Jan 03 '23 16:01

Matthias Bauch


Moving [super viewDidDisappear:animated]; to the end of your method may be the most expedient way to address the problem. If that does not work, move the logic into viewWillDisappear:animated:.

A better way to deal with this would be to avoid reading the current state from the view at all. Rather, the view should pass the state to the model on each update. This way you would be able to harvest the current state from your model, entirely independently from the state of your view.

like image 37
Sergey Kalinichenko Avatar answered Jan 03 '23 18:01

Sergey Kalinichenko