Joe
Joe

Reputation: 279

How to get UITextField (subview to UITableViewCell) text value when tableview cell became invisible

I created a custom UITableViewCell class that embedded a UITextfield to each cell, in the addItemTableViewController, I want to get text values within all UITextField-embededd cells and create a new model object, but I'm running into a problem:

cellForRowAtIndexPath returns nil for invisible cells, after I scrolled down to the buttom of my tableview then hit the Add button, the first a few rows' textField text value became null.

Is there anyway I can fix this? I've been Googlging for hours and still not find a answer for it.

Here's my addItemTableViewController code:

    - (IBAction)doneAdd:(UIBarButtonItem *)sender {
        [self.delegate addItem:[self newItem]];
    }

    - (NSMutableArray *)newItem
    {
        NSMutableArray *newItem = [[NSMutableArray alloc] init];

        for (int i = 0; i < [_appDelegate.title count]; i ++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
            UPFEditableUITableViewCell *cell = (UPFEditableUITableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
            NSLog(@"%@", cell.editField.text);
            //[newItem addObject:cell.editField.text]; //this does not work as null cannot be added into a array
        }
        NSLog(@"%@", newItem);
        return newItem;
    }

Here's my custom UITableViewCell class implementation

    #import "UPFEditableUITableViewCell.h"

    @implementation UPFEditableUITableViewCell

    - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        if (self) {
            self.editField = [[UITextField alloc] initWithFrame:CGRectZero];
            [self.contentView addSubview:self.editField];
        }
        return self;
    }

    - (void)layoutSubviews
    {
        if ([self.detailTextLabel.text length] == 0) {
            self.detailTextLabel.text = @" ";
        }

        [super layoutSubviews];

        // place the edit field in the same place as the detail text field, give max width
        self.editField.frame = CGRectMake(self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.origin.y, self.contentView.frame.size.width-self.detailTextLabel.frame.origin.x, self.detailTextLabel.frame.size.height);
    }

    - (void)showEditingField:(BOOL)show
    {
        self.detailTextLabel.hidden = YES;
        self.editField.text = self.detailTextLabel.text;
    }


    @end

Upvotes: 2

Views: 4907

Answers (4)

Joe
Joe

Reputation: 279

I think made a fundamental mistake, have my view talks with the model layer, what a lesson learned...

anyway, I managed to work out a solution, in short, here's what I did:

  • made cell as the delegate of the UITextField
  • implemented textFieldDidChange, to capture textField changes, once there's a change, submit the changed content to the model

And here's the code:

in the cellForRowAtIndex:

    [cell.editField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
     cell.editField.delegate = self;

and here's the code for the textFieldDidChange:

    - (void)textFieldDidChange :(UITextField *)theTextField
    {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        [self.item removeObjectAtIndex:indexPath.row];
        [self.item insertObject:theTextField.text atIndex:indexPath.row];
    }

Upvotes: 3

AppleDelegate
AppleDelegate

Reputation: 4249

This is not a problem.The cell are dequeud and reused whenever new cells are created.Hence while scrolling the tableview at the top they become null and the new cells are created with the same identifier.

For your problem you will need to store the value of textfield's value into a dictionary.For this you will need to save it at the time you are dequeing the cell.

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

static NSString *cellReuseIdentifier = @"cellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];

    if (!cell) {
               cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];

    }else{
        NSLog(@"text is %@",cell.textLabel.text);

for (UIView *v in cell.contentView.subviews) {
        if ([v isKindOfClass:[UITextField class]]) {
            UITextField *textField = (UITextField *)v;
        [myDictionary setObject:textField.text forKey:indexPath]; // declare myDictionary in the interface first.This will also prevent the values from duplicating
  NSLog(@"%@",myDictionary);
        }
      }
    }
return cell;
}

Upvotes: 1

borncrazy
borncrazy

Reputation: 1599

You should always try to save the data in model classes and use the array of these model class instances to load the table. So that you don't need the tableCells to get the data after that. The datas are always to be fetched from models and not the UIs (TableCells in this case).

You might be loading the tablecell initially using an arra,y. If so, use that array to create the model class objects you mentioned instead of the tablecells.

Upvotes: 0

Szu
Szu

Reputation: 2252

To get value from UITextField you can set the delegate on your ViewController. Then you should implement textField:shouldChangeCharactersInRange:replacementString: where you can update NSString value.

The second solution might be keeping reference to the each cell in NSMutableArray.

Anyway you try to avoid calling cellForRowAtIndexPath: from table view controller.

Upvotes: 0

Related Questions