Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Dynamic Form in UITableViewCells, Retrieve Values

I have been searching and reading all over but couldn't find any conclusive method to achieve what I want to and hope to find help here...

I have a UITableView which allows the user to add multiple Flavours and Percentages to a Recipe. I have implemented the method to add or delete rows of Flavours with a custom Cell / Nib and it works perfectly well.

The issue I'm facing now, is how to retrieve the values the user has provided per added row.

(Edit for Clarity: My problem is not the populating of data, but only the dynamic reading of all data so I can save it)

I do manage to get the values for the visible rows (I do understand how the Reuseidentifier and the Tableview works, per se that for memory management's sake, iOS only keeps track of the visible rows), but not the hidden ones.

I assume in theory that I have to create an Array of Cells outside of 'cellForRowAtIndexPath' which maintains all cells. But then I'm facing another conceptual problem that my custom Nib / cell doesn't show.... basically:

  • How can I then use / register a nib without using the dequeingidentifier
  • Or in General, how can I solve the overall problem to be able an read all user entered values per row

Screenshot TableView

Here the code I'm using within my cellForRowAtIndexPath. As mentioned adding and remove cell works like a charm, that isn't the issue...

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

RecipeFlavourTableViewCell *cell;
int section = (int)indexPath.section;

if(section==0)
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];


if(!cell){
    [tableView registerNib:[UINib nibWithNibName:@"RecipeFlavourCell" bundle:nil] forCellReuseIdentifier:@"Cell"];
    cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
}

cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;

}

I have seen some Libraries doing it (e.g. XLForm) but do not understand (also when checking their sources) how they iterate through the values and overcome this dequeuing problem...

Any help is highly appreciated

EDIT 2: here the code I'm using to iterate through the cells in order to save the data, but as said I can only iterate through the visible cells:

- (IBAction)saveRecipe:(id)sender {

NSInteger dynamicRows = [self.tableView numberOfRowsInSection:1];

    for (int i=0; i<dynamicRows; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:1];
        RecipeFlavourTableViewCell *cell = (RecipeFlavourTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        NSLog(cell.flavour.text);
    }

}

like image 743
DonBaron Avatar asked Feb 28 '26 00:02

DonBaron


1 Answers

After 2 days of searching I finally came up with a solid solution. In case someone bumps into the same problem of dynamic forms with a tableview, here the solution:

As we understand, what ever cell is created in cellForRowAtIndexPath, it only persists as long as it is displayed. As soon as you scroll and the cell disappears, it gets automatically thrown out of memory. This behaviour makes it impossible to iterate through all cells at a later stages.

The steps to follow in order to make it work are as follows:

Preparation

  • Create an NSObject with all properties you want to persist in one form cell (-> cellObject)
  • In the ViewDidLoad of your controller create a NSMutableArray which will contain the cellObjects (-cellsArray)
  • Add as many cellObjects to the cellsArray as you initially want to appear in the Tableview
  • In numberOfRowsInSection return the count of you cellsArray
  • In the cellForRowAtIndexPath build your cells as usual BUT add a Textfield Delegate (self) to every Textfield in a cell

TextField Delegate

Implement:

 - (void)textFieldDidEndEditing:(UITextField *)textField

and update your cellsArray Objects every time a Textfield ends editing. Per se, get the cellObject for the row and edit the properties with the value of the TextField

Add Row

When ever you add a row, just add an empty cellObject to your cellsArray and use the beginUpdates / insertRowsAtIndexPaths / endUpdates on your tableView (NOT reloadData as the already typed in data would get lost). Also add the following at the very beginning of your addRow method, as you want to make sure that if the user adds a row while editing a textfield, the latter gets persisted as well:

 [self.view.window endEditing: YES];

Remove Row

Same as Add Row just reverse, remove the cellObject from your cellsArray and use deleteRowsAtIndexPaths on your tableView

Save Data

Now comes the trick: since you ought to always persist your data when a field ends editing mode, there is one case you need to cover: What if the user pushes "Save" when the focus is set on one TextField? Well at the very beginning of your Save Action insert the following:

 [self.view.window endEditing: YES];

This make sure the the textFieldEndEditing will be triggered one last time for the current textField and that its data will also be persisted.

Finally iterate through your cellsArray and do whatever you want with it (validate, save etc)...

That's it, hope this can help anyone else as I couldn't find any valuable explanation anywhere else...

like image 116
DonBaron Avatar answered Mar 02 '26 14:03

DonBaron



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!