Search code examples
iphoneiosuitextviewuiswitch

UITextField artifacts


I have an iPhone app which has a Table View-based data input screen with a toggle, which when on shows all rows in another section of the table.

Sometimes, when the app is first loaded, and usually when it has been fully deleted from the phone, the UITextFields from the original section of the table are displayed in addition to the new rows, as below (main table section is above)

enter image description here:

THe strangest thing about this is that this behaviour only occurs the first time this screen is displayed - it seems fine after that. Oh, and it only seems to occur on the phone, not the simulator.

Given the random nature of this, could it have something to do with other apps? I did have apps with similar namespaces running at the same time. The problem seemed to go away after I closed the apps down / deleted from phone.

I have included the code block that is run when the switch is changed below:

- (void)accountSwitchChanged {
[customerDetails saveField:@"addToAccount" WithBool:addToAccountSwitch.on];

NSArray *indexes = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:1], [NSIndexPath indexPathForRow:2 inSection:1], [NSIndexPath indexPathForRow:3 inSection:1],nil];

if (addToAccountSwitch.on)
    [detailsTable insertRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationFade];
else
    [detailsTable deleteRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationFade];
}

Any ideas?

--EDIT

cellForRowAtIndexPath code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get rid of grey background for iPad app
[tableView setBackgroundView:nil];
UITableViewCell *cell = nil;
NSDictionary *cellData = [[dataSourceArray objectAtIndex: indexPath.section] objectAtIndex:indexPath.row];

id cellControl = [cellData objectForKey:kCellControlKey];

    static NSString *kCellControl = @"CellControl";
    cell = [tableView dequeueReusableCellWithIdentifier:kCellControl];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellControl] autorelease];
        cell.textLabel.textColor = [[[ConfigManager sharedInstance].skin valueForKey:@"tableCellHeadingTextColour"] toUIColor];
        cell.backgroundColor = [[[ConfigManager sharedInstance].skin valueForKey:@"tableCellBgColour"] toUIColor];
        cell.textLabel.font = [UIFont boldSystemFontOfSize:17];
    } else {
        // a cell is being recycled, remove the old control (if it contains one of our tagged edit fields)
        UIView *viewToCheck = nil;
        viewToCheck = [cell.contentView viewWithTag:kDetailsViewTag];
        if (!viewToCheck)
            [viewToCheck removeFromSuperview];
    }

    // if control is not a text field, make it a button
    if (![cellControl isKindOfClass:[UITextField class]])
        cell.selectionStyle = UITableViewCellSelectionStyleGray;
    else
        cell.selectionStyle = UITableViewCellSelectionStyleNone;

    cell.textLabel.text = [cellData objectForKey:kCellTitleKey];
    [cell.contentView addSubview:cellControl];

return cell;
}

Solution

  • Something to check and eliminate If it is only occurring the first time view is displayed, it's always worth checking whether you are assuming the view is loaded before you are doing work on it. This doesn't come up very often, but when it does it can be very hard to track down. To check whether this might be your issue, add a [viewController view] call just after you create the view for the first time. This forces the view to be loaded. If the issue goes away when you add this, you've tracked the source of the issue. And you can even leave the [viewController view] call in as a fix, or work through your code to allow for lazy instantiation.

    All this said, far more likely to be something funny in your tableView:cellForRowAtIndexPath: code. If you want good stack overflow, post all or relevant fragment of the that code (or the relevant code it calls).

    Follow up on posted code:

    (1) if (!viewToCheck) [viewToCheck removeFromSuperview] won't do anything. It'll only send a removeFromSuperview message when viewToCheck is nil and that won't do anything. Not sure if this will be key issue, but it's something to put right.

    (2) [cell.contentView addSubview:cellControl]; - this looks problematic - it's usually best to only add subviews when you create the cell. You can hide or show in the main body of tableView:cellForRowAtIndexPath: - that would, I suspect, work for you here. With this code there's a risk here that you'll either add multiple subviews when you only want one or (which may be what's going on here) that you end up not removing a subview when a cell is recycled. If the viewToCheck code is supposed to be removing the added cellControl then, as (1), it won't do that just now because your if condition is wrong.