Best approach for editing text fields in a table view cell - ios

In my app I've got a number of views that need to be in-place editable. I've got the tableviewcells setup to include a UITextField which is enabled, and the text can be changed and this is fine, it works.
My question is what is the best approach to keeping track of these? Should I :
Keep an iVar of each textfield. If so then
How do I make sure each cell has the correct field if it's only instantiated once?
Have a textfield added when the cell is created and simply set its value when configuring the cell. If so then
How do I keep track of the values? If the cell went out of view and then back, its values would be reset to its original value and not the edited value.
What approach do you generally tend to use for this scenario? Especially if there are a large number of cells that you're dealing with.

Store the values for all of your text fields in a mutable array in your data model.
In tableView:willDisplayCell:forRowAtIndexPath: set your text field's value, using the value from your array based on the index path.
When a text field ends editing, store the value back in the array immediately. There is already a protocol for this (so no need to write your own), but it is a little trickier than normal because you are not handed the indexPath and need to find the one associated with your text field:
- (void) textFieldDidEndEditing:(UITextField *)textField {
CGRect location = [self convertRect:textField.frame toView:self.tableView];
NSIndexPath *indexPath = [[self.tableView indexPathsForRowsInRect:location] objectAtIndex:0];
// Save the contents of the text field into your array:
[yourArray replaceObjectAtIndex:indexPath.row withObject:textField.text];
}

Subclass UITableViewCell and add a UITextField in it's init method.
create a protocol for the custom cell class. when UITextField begin editing or end editing call the delegate's method.
in controller, implement the custom cell's protocol and set the indexpath row value to cell's tag in tableView:cellForRowAtIndexPath:
so every time you edit UITextField, you can know in controller which row is editing (via cell's tag)

The best way is to follow MVC and implement your model, which in your case is the textfield values. What you do is store those values in an array, and in your cellForIndexPath method you reference the correct value in the array. For example, the first row of the table (indexPath.row == 0) would retrieve the first element in the array. Changes in the textField would be recorded on the corresponding element in the array.

Related

Odd behavior iterating through UITableViewCells

I have user input a form based on a UITableView where each cell contains an input control, either a UITextField or a UITextView. I've added Next and Previous buttons to the accessory views of the text fields so that users can navigate forward and backward through the text fields. I have a method that gets the control of the text fields and makes it first responder. Everything so far works properly.
In my method that sets the first responder, I'm calling a helper method that gets the next cell, going either forward or backward:
- (UITableViewCell*)nextFormCell:(UITableViewCell*)lastCell isForward:(BOOL)forward
{
NSIndexPath* path = [_formTableView indexPathForCell:lastCell];
NSInteger rowIndex = forward ? (path.row + 1) : (path.row - 1);
UITableViewCell* nextCell = [_formTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:rowIndex inSection:path.section]];
return nextCell;
}
Going forward (next) works flawlessly and this method always returns a cell. However, going backward (previous), the method sometimes returns nil. I have verified that rowIndex contains the correct value going both directions. This doesn't make great sense. If I pass a rowIndex going forward and I get a cell back, why would it not do the same with the same index going backward?
Are there any known issues with navigating backward through UITableView cells? Thanks!
You are forgetting that cells are reused. No cells exist at any given moment except for those displayed on the screen and possibly one or two further forward. cellForRowAtIndexPath: does not work for every index path, because not all cells exist at any one moment: only the cells actually displayed by the table exist. That is why cellForRowAtIndexPath: is permitted to return nil.
Basically you need to rethink your entire strategy for "navigating" the table. Instead, start by scrolling to the cell you want to navigate to (scrollToRowAtIndexPath:atScrollPosition:animated:). Now the cell exists and you can set its text field as first responder.

how to save the content of a uitextview to a tableview

I have a UITextView and when I press a 'Save' button I would like that the text will get added to a row in my UITableView. I've set up the table view already. I'd also like to get to the UITextView when selecting one on the table view.
First, you need to add the data to your data source. Depending on how your table is set up that might just entail adding an extra string to an array, if you edit your question with more detail I can be more specific here.
Next you call insertRowsAtIndexPaths:withRowAnimation: on your table view, changing the value of the index path depending on where you've added the new data.
[tableView insertRowsAtIndexPaths:#[NSIndexPath indexPathForRow:0 inSection:0] withRowAnimation:UITableViewRowAnimationAutomatic];
The table view will take care of the rest, it will call cellForRowAtIndexPath: to make the new table cell (using the data you just added to the data source) and will even animate it into position for you.
For the second part of your question, you'll need to implement tableView:didSelectRowAtIndexPath: and in there get the appropriate string from your data source based on the selected row, and set the text view accordingly. Something like
textView.text = myDataSourceArray[indexPath.row];
Very basic, but this example should do the trick.
https://cloud.jakota.de/public.php?service=files&t=922500d0732da5ce3cc71b6fdf517a83

How do I get information from a UITableViewCell?

I have a TableView with a prototype cell, in this prototype cell I have a text field.
Well, what I need is to get a information from this text field when it changes. I need to do that to feed a object.
How can I do that ?
Short answer - you don't.
Slightly more in depth answer...
The UITableViewCell is a "view". It is used only to display information to the screen. It is not for storing data in.
In a UITableViewController (i.e. UITableViewDatasource and UITableViewDelegate) you should have an NSArray (or an NSFetchedResultsController) that you use to store information in.
Then using the delegate methods you populate the table with that data.
If the data changes then you reload the table to update the cells.
What should never happen is the following...
Load the table by passing in data to the cell.
The cell then changes its own data and changes what is on the screen.
The controller then reads that data out of the cell.
No, no, no, don't do this.
What should happen is this...
Load the table and configure the cell display to represent the correct part of the data.
When the button is pressed (or text field is changed, etc...) in the cell then call a method back in the controller to update the data accordingly.
Now the data has changed, reload the cell.
It will now show the correct information based on the new data.
You need a custom cell with a public property (IBOutlet) UITextfield. Then you can set your ViewController as the textField's delegate in cellForRowAtIndexPath,
cell.textField.delegate = self;
in this case your ViewController has to implement UITextFieldDelegate protocol.

How can I get the value of a UITableViewCell that is not visible?

I have a table view cell that has many rows with a UITextView. In those UITextView the user can enter values.
The problem that I have is that if I want to get the value of a row when the row is hidden I get nil.
NSString *cellValue = ((UITextField *)[[[self.table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]] contentView] viewWithTag:[self.table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]].tag]).text;
I was thinking to save the value that the user enters in the UITextField, but if the user clicks a row that performs the calculate the delegate textFieldDidEndEditing is not being called.
I don't know how can I get this values in a secure way.
You should target the data source that is behind the UITableView. The UITableView is just a display mechanism and not the primary resource for getting to data. You can get the index for the cell based on the title, but then I would look tot he data source to get your actual data. Better yet I would just handle all operations against the data source itself if that is possible. When you build the table initially your data source is a list or array of some kind I am sure so you can just use it. You may need to create a variable on the view and retain the list/array there to make sure you have it and you should be all set.
Good Luck!
As mentioned, you would generally use the UITableView data source to access this.
That said, you are probably not seeing the data you expect because the you are using dequeued cells. If the number of cells is small, you could consider caching your own cells in an NSDictionary whose keys are some combination of the section and row, and accessing their view hierarchy via your own cache.
You can access rows that are not currently displayed by directly referring the tableView's dataSource with the wanted IndexPath.
You can achieve this by doing something like this (when using Swift 3):
UITableViewCell cell = self.tableView(self.tableView, cellForRowAt: indexPath)
What is happening most likely is your reusing cells. So when your cell with the textfield goes off screen it gets reused so you cannot access it anymore. What you will need to do is grab the value out the the textfield right after they enter it and store it somewhere. You can use – textField:shouldChangeCharactersInRange:replacementString: so that when ever the user enters a character into the textfield you can save the string.

Saving data from custom UITableViewCell

I have an edit screen which is comprised of one huge UITableView.
Each cell in the table is a custom UITableViewCell comprising of a UITextField
I am able to load up the table, scroll around and enter information. However, during scrolling the table cells lose the data entered and I understand why this happens.
I realize I need to save the data as soon as the user finishes entering the data using the textFieldDidEndEditing method.
Question: I want to store the data entered in a custom object that is available in the ViewController - how do I access this from the UITableViewCell? Also, how do I identify the row and position of the table cell so that based on the position I can populate a specific attribute in the object
Question: Am I doing this the right way? Or is there a better way to do this?
As you are mentioning only a single text field, we can make do with an NSMutableArray object containing strings for each cell. You will have to fill the array with empty strings and use this info to fill the text field. It will be something like,
textField.text = [textFieldStrings objectAtIndex:indexPath.row];
Since you're doing it programmatically within the view controller, you will have to set the view controller as your text view delegate. You can do
- (void)textFieldDidEndEditing:(UITextField *)textField {
UITableViewCell *cell = (UITableViewCell*)textField.superview;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
... Since you've the index path, you can map it to an array.
[textFieldStrings replaceObjectAtIndexPath:indexPath withObject:textField.text];
}
This would be the basic idea. Start with a mutable array of empty strings and modify them every time the text field is updated by replacing the original text with the new text. Hope this helps.

Resources