Search code examples
objective-cuitableviewretain

UITableView cell retaining out of view data


I am trying to solve this issue regarding a UITableView cell being off screen, or outside the visible area.

Within my tableview cells I have a UITextField which I am able to parse easily using the code below. However I find that that for the cells that are not visible it returns a NULL value.

I am guessing this is a feature to improve memory usage but is there anyway to turn it off? Or if not is there a work around?

InputCell *inputCell = (InputCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
UITextField *cellContent = (UITextField *)[inputCell.textInput viewWithTag:0];

NSLog(@"Cell Content: %@" , cellContent.text);

Thanks and thanks again!


Solution

  • Views need models, especially table views. A model is some object (often a group of objects in collection classes) that represents the state of your app. A table view requires an array. The datasource protocol asks you to describe that array. Since tableview cells are part of the view, they shouldn't be relied upon to keep the state of your app. That's up to you as follows:

    In your vc's private interface:

    @property(strong, nonatomic) NSMutableArray *myDatasource;
    

    Early, like in view did load:

    myDatasource = [NSMutableArray array];
    // fill it with strings
    

    In numberOfRowsInSection...:

    return self.myDatasource.count;
    

    In cellForRowAtIndexPath:

    cellContent.text = self.myDatasource[indexPath.row];
    

    Make the vc your textField's delegate and implement:

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    
        NSString *candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    
        NSIndexPath *indexPath = [self indexPathWithSubview:textField];
        self.myDatasource replaceObjectAtIndex:[indexPath.row] withObject: candidateString];
        return YES;
    }
    

    This helper finds the indexPath of any textField (any subview) of any cell:

    - (NSIndexPath *)indexPathWithSubview:(UIView *)subview {
    
        while (![subview isKindOfClass:[UITableViewCell self]] && subview) {
            subview = subview.superview;
        }
        return [self.tableView indexPathForCell:(UITableViewCell *)subview];
    }
    

    It looks like a lot, but not so bad when you get used to it. The pattern is always - think of the objects that describe the state of your app (model). Think of views that best describe and manipulate that state (view). Make your view controllers (controllers) (a) notice model changes and change the views accordingly, and (b) hear about user actions from the views and update the model.