2

I have created a table which dynamically creates cells which are customized to contain a textField. When I run the program, I am able to enter text into the textFields. However, I am not able to collect the text entered into them before quitting the program/switching to a different viewController. Can you please suggest what I should do in order to extract the text entered by the user.

I understand that I can access the cells using the following code...

for (int section = 1; section < [self.tableView numberOfSections]; section++) // section 0: profile picture
{
    for(int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++)
    {
        NSLog(@"section = %d, row = %d", section, row);
        NSIndexPath *tempIndexPath = [NSIndexPath indexPathForRow:row inSection:section];
        UITableViewCell *tempCell = [self tableView:self.tableView cellForRowAtIndexPath:tempIndexPath];
//            NSLog(@"tempCell = %@", tempCell);

    }
}

But I am not able to extract the text contained in them.

I also referred to: Accessing UITextField in a custom UITableViewCell. But I am looking for a cleaner solution.

Thanks!

Community
  • 1
  • 1
Rutvij Kotecha
  • 935
  • 2
  • 10
  • 21
  • Have you tried to make your textfield with getter setter, using @ property in custom cell class, and access these using tempcell.yourtextfield.text. – josh Dec 24 '12 at 12:29

3 Answers3

1

The link that you refer to is very close to what you need to do, however there is a better way to get the indexPath.

A common mis-conception when starting with iOS programming is that you need to get all of the values of the text fields at the time you need the data (such as when the user hits "Submit"). The problem, especially when they are in a table, is that the text fields are not always available. If the cell is off the screen, it quite possibly doesn't exist, or it has been reused in a different row of the table. Text fields are view's which are supposed to display data, and not act as your model where you store it.

So, the first thing that you need to do is to make your view controller conform to the UITextFieldDelegate protocol and set the delegate of the textfield when you create it to your view controller:

Your .h file (the <UITextFieldDelegate> is the important part):

@interface YourViewController : UIViewController <UITextFieldDelegate>

When you create your text field:

myNewTextfield.delegate = self;

This tells the text field to inform you of important changes to it. Now, you only need to create the text field delegate method which is called as soon as they finish editing the text field and wait for it to be called so that you can store the text:

- (void) textFieldDidEndEditing:(UITextField *)textField {
    // If you need the index path of the table view cell which contains the text field in order to know how to store it, use:
    CGRect position = [self convertRect:textField.frame toView:self.tableView];
    NSArray *indexPaths = [self.tableView indexPathsForRowsInRect:position];
    NSIndexPath *indexPath = [indexPaths objectAtIndex:0];

    // Save the contents of the text field somewhere so that you have it later when you need it:
    something = textField.text;
}
lnafziger
  • 25,760
  • 8
  • 60
  • 101
  • How could you set the text field delegate to self when the text field exists inside the cell class? The cell class wouldn't have access to the interface because it's in the UIViewController, not in the cell class. – Hedylove Mar 12 '18 at 00:26
  • @JozemiteApps That's why I suggested making the view controller the delegate of the text field.... – lnafziger Mar 12 '18 at 15:40
  • Don't you mean then: `cell.myNewTextField.delegate = self`since text fields does not exist in controller. – Hedylove Mar 12 '18 at 18:49
0

This tutorial was helpful to me. You can reference whatever object you need through the tag.

In the Storyboard drag on a UIImageView or UITextField etc. and set the tag to 100 (whatever you want) then in your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath use the tag to reference it.

Here's something you could do, just remember to set the tags in the storyboard:

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

// Configure the cell...
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

 UITextField *tField = (UITextField *)[cell viewWithTag:100];

return cell;
 }
SirRupertIII
  • 12,324
  • 20
  • 72
  • 121
0

Here's my Swift 4 solution since I was having the same issue.

I too added text fields into cells and the table is created dynamically, so the table view controller doesn't have any direct access to the text field.

First, I created a protocol that will allow the table view controller to keep the data saved of the inputted values of the cell's text fields.

protocol SMTextFieldRowCellProtocol: class {
    var dataValues: [String: String] { get set }
    func updateDataValues(with data: [String: String])
}

In the cell's custom class, add the following delegate property:

var delegate: SMTextFieldRowCellProtocol?

Still in the cell's class, make it conform to UITextFieldDelegate, set the text field's delegate to self in the awakeFromNib().

textField.delegate = self

Then in the cell's class, add the UITextFieldDelegate's method and make it call the updateDataValues method. I made my keys equal to the title label of the cell, so all key's are unique.

func textFieldDidEndEditing(_ textField: UITextField) {
    delegate?.updateDataValues(with: [titleLabel.text!: textField.text!])
}

The above method will update the dictionary of the table view controller. Almost done, but whenever you're making the rows in the table view's cellForRow method, set the cell's delegate:

cell.delegate = self

Finally, add the protocol to the class and conform to it:

class SMEditProfileTVC: UITableViewController, SMTextFieldRowCellProtocol {
    var dataValues: [String: String] = [String: String]()
    func updateDataValues(with data: [String: String]) {
        for key in data.keys {
            dataValues[key] = data[key]
        }
    }
}

So what is happening is when you are done editing the text of a cell, it will call the table view controller's updateDataValues method and save the data into the dataValue's dictionary. Now this will make it easy to transfer the data when saving, etc. or when they're done in the view controller.

Hedylove
  • 1,724
  • 16
  • 26