views:

34

answers:

2

Hi there! I have following problem: I've got an UITableView with 7 custom cells. Each of these cells hold a label and an UITextField in it. Since the cells are somewhat big, you have to scroll down to see the last 3 cells. The problem is, as soon as I scroll down, the text in the textfields of the first 3 cells (those, that aren't visible then) gets removed. All that is left is the placeholder. The same goes for the last 3 cells, as soon as I scroll back up. The textfield in the 4th cell retains its text just fine, since its always visible. Does anyone have an idea how to solve this problem?

Best regards.

UPDATE: Here's the code for the corresponding comment:

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

NewXYZTableCell *cell = (NewXYZTableCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil){
    NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NewXYZTableCell" owner:nil options:nil];

    for(id currentObject in topLevelObjects)
    {
        if([currentObject isKindOfClass:[NewXYZTableCell class]])
        {
            cell = (NewXYZTableCell *)currentObject;
            break;
        }
    }
}

switch (indexPath.row) {            
    case 0:
        cell.myLabel.text = @"XYZ";
        // and so on... 
    default:
        break;
}   
return cell;}
+1  A: 

You probably use the dequeueing mechanism to populate the UITableView with its cells. This means that a cell that has been allocated and is currently off the screen can be reused and filled with other content. This saves you the performance costs of allocating a new cell for each row. So even table views with a lot of cells can perform very well, because it only has to deal with, say, six or seven cells at the same time.

And this probably is also what happens to you. Your cells get scrolled off the screen and are now free to be reused by the new cells coming to the screen (displaying different contents). So you will have another title and another (new) text field. So you need to save your input somewhere if a cell gets scrolled off the screen. For example, you can listen to a UITextFieldTextDidChangeNotification.

Register your controller as an observer, e.g. in -viewDidLoad: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldChanged:) name:UITextFieldTextDidChangeNotification object:textField]

And then implement your method, in this case textFieldChanged:, which takes an NSNotification* as parameter and save your input:

-(void)textFieldChanged:(NSNotification *)notification {
    ...
}

Don't forget to reinsert the input to your cells if they are scrolled back on the screen.

Another option is to not use dequeueing and create all cells as soon as they are needed. This might be a better idea if you have only very few cells. You need to take care then to return the correct cell in -cellForRowAtIndexPath:.

muffix
Thank you for this quick and also helpful response. I was already storing the text values (but without the NotificationCenter; isn't the best idea to use for what I want to accomplish), but didn't think of the idea to populate the textfields again with those values when they come in sight of the screen. Since there are only 7 cells, what would be the faster approach? To repopulate or to not use dequeueing?
zhar
With only seven cells and if this is a fixed number, it is probably faster to allocate and keep all those in memory even if some are not currently displayed. You won't run into memory issues and yet have quick access to them.
muffix
Thank you very much. Will try this right away.
zhar
For unknown reasons, the issue is everytime the same, regardless of what I try. I posted the original code above. Could you please give me a hint in how to accomplish the task of allocating? Thanks in advance!
zhar
A: 

Posting this as new answer, so I can make use of code formatting.

My suggestion is to save the seven cells in seven instance variables and create the appropriate getters. So, in your .h file you declare the variables:

NewXYZTableCell *cell0;
...
NewXYZTableCell *cell6;

In your implementation, write a getter:

-(NewXYZTableCell*) getCellNumber:(int)cellNumber {
    NewXYZTableCell *cell;
    switch (cellNumber)
    {
        case 0:
            cell = cell0;
            break,

        ...

        case 6:
            cell = cell6;
            break,
    }

    if (cell == nil){
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NewXYZTableCell" owner:nil options:nil];

        for(id currentObject in topLevelObjects)
        {
            if([currentObject isKindOfClass:[NewXYZTableCell class]])
            {
                cell = (NewXYZTableCell *)currentObject;
                break;
            }
        }
    }
    return cell;
}

This getter will return the cell with the corresponding number after creating it, if it did not exist before. Then you can make use of it in -tableView:cellForRowAtIndexPath::

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    return [self getCellNumber:indexpath.row];
}
muffix