0

I have a UITableView which act as a form. It has about 20 cells (with static content but dynamic cells). So I had an array with the fields and loading it in the table view. At some time the user will press the "Submit" button and I need all the textfields values that entered in the tableview's cells. So I created a @property for each textfield in each cell and I am assigning it in the cellForRowAtIndexPath:.

 if (indexPath.row==RPCVehicleType || indexPath.row==RPCExcess || indexPath.row==RPCDrivers){

    static NSString *tableIdentifier = @"TextFieldArrowCell";

    TextFieldArrowCell *cell = (TextFieldArrowCell*)[tableView dequeueReusableCellWithIdentifier:tableIdentifier];

    if (cell == nil) {
        cell = [[TextFieldArrowCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableIdentifier];
    }

    switch (indexPath.row) {
        case RPCVehicleType:
            self.typeOfVehicleTextfield = cell.valueField;
            break;
        case RPCExcess:
            self.excessTextfield = cell.valueField;
            break;
        case RPCDrivers:
            self.driversTextfield = cell.valueField;
            break;
        default:
            break;
    }

    return cell;

The problem with this code is that when I scroll to the bottom the cells are being reused and the properties are messed. So when I do [self.excessTextField setText:@"123"] the first time it's ok but after scrolling and execute again I can see other textfields of the same type of cell to change to that value. Any workaround to solve this issue?

Update: Tried this approach with the same result:

-(UITextField*)getTextFieldForRow:(NSInteger)row{

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
TextFieldArrowCell *cell = [self.tableV cellForRowAtIndexPath:indexPath];

return cell.valueField;

}

BlackM
  • 3,927
  • 8
  • 39
  • 69
  • Maybe you should use common approach and save your data to and array and populate your table view with it, based on `indexPath` like that: `someTextField = backingArray[indexPath.row]` – schmidt9 Mar 24 '16 at 08:39
  • That's not a problem. This is what I am doing. The problem is saving data from table view – BlackM Mar 24 '16 at 08:43
  • I suppose you get the same values because you refer to the same objects. Try `self.typeOfVehicleTextfield = [cell.valueField mutableCopy]` – schmidt9 Mar 24 '16 at 08:52
  • This wont work since I need to keep up to date the pointer on the specific textfield on the specific cell in case the user update the value. – BlackM Mar 24 '16 at 08:55
  • Add all the fields to an array, so you keep all refs – schmidt9 Mar 24 '16 at 09:01
  • This problem because of the reuse tableview cell. The good way that you need use method " (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath" to get the cell . Then you cast to your "TextFieldArrowCell" and get text or set text from label. – Martin Le Mar 24 '16 at 09:15
  • Already tried that. I have updated the question. – BlackM Mar 24 '16 at 09:31
  • Use `dequeueReusableCellWithIdentifier:forIndexPath:`. Your code will look better. – Damian Rzeszot Mar 29 '16 at 15:26

4 Answers4

3

You can only retrieve data from visible cells (invisible cells don't exists or they have inappropriate data).

There are several ways to do it. For you, the best solution would be to delegate (UITextFieldDelegate). You can obtain information about changes in UITextField, so you can update your data model.

In tableView:cellForRowAtIndexPath: you pass correct (actual) data to table cell (this part of code you already have).

Damian Rzeszot
  • 548
  • 3
  • 12
0

I can see 2 possible approaches to solve your problem.

Possible solution 1

Use your own cell without reuse them, in this case you will always have access to the information stored in the text field.

Here is a sample code in Swift, easily translatable to Objective-c

var myCellArray:[TextFieldArrowCell?] = Array.init(count: 3, repeatedValue: nil)

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!  {

        if (myCellsArray[indexPath.row] == nil) {
            myCellsArray[indexPath.row] = UITableViewCell(style: .Default, reuseIdentifier: "TextFieldArrowCell") as! TextFieldArrowCell

        //Config the cell

        }
        return myCellsArray[indexPath.row]
    }

At the end, in the save button, just consult your array, and read the data of the text field.

Possible solution 2

When prepare for reuse the cell, store the data.

You can add to you cell object this function, so when the cell is about to be reuse, you have to check the data and store somewhere else.

override func prepareForReuse(){
    // save data here an then....
    super.prepareForReuse()
}
Ulysses
  • 2,281
  • 1
  • 16
  • 24
0

Let's say you have an array of Objects where each object corresponds to form field in your tableView. When you dequeue a cell you need to assign corresponding object to your UITableViewCell subclass. Now make your UITableViewCell subclass a receiver for

UITextFieldTextDidChangeNotification

and save changes to your model.

I.e. it would look something like this.

@interface MyObject: NSObject 
@property (strong, nonatomic) NSString *someValue;
@end

// Dequeue your cell..
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

   MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
   // Assign an object to your cell
   cell.object = arrayOfObjects[indexPath.row];
   return cell;
}

// Register cell as an observer

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    if (self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]) {
    // Your init code
    [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidChangeNotification
                                                object:self.textField
                                                       queue:[NSOperationQueue mainQueue]
                                                      usingBlock:^(NSNotification * _Nonnull note) {

                                                          if ([note.object isEqual:self.textField]) {
                                                              self.object.value = self.textField.text;
                                                          }
                                                      }];

    }
}
Josip B.
  • 2,434
  • 1
  • 25
  • 30
  • Can you elaborate please? I didn't understand how to make this code work with the tableview – BlackM Mar 24 '16 at 10:03
  • The code is for the object or the cell? It seems like object – BlackM Mar 24 '16 at 10:04
  • No, this code is pseudocode for 3 different parts of your UITableView. First part describes how should your model look like (the one which should store your data). Second part describes how should you assign your object to your UITableViewCell subclass called MyCell. Third part describes how should you catch changes of your UITextField using NSNotificationCenter and saving those changes to your model. This approach saves all UITextField changes to MyObject models which are in the end contained in some array in your ViewController. – Josip B. Mar 24 '16 at 10:07
0

provied each cell a diffrent identifire like tableIdentifier = [string stringwithformat:"cellid%@",indexpath.row]. Hope this will help you.

Prabhat
  • 96
  • 7
  • That won't work. I need to clone the Cells in the Storyboard and set the different identifiers. So it's better to use static cells in that case – BlackM Mar 24 '16 at 10:24