Custom UITableViewCell with UITextField : textFieldDidEndEditing is too slow - ios

I have a custom UITabelViewCell class that also implements UITextFieldDelegate
I also implement textFieldDidEndEditing so that once a field is done being edited I get a call back so that I can store the value that was typed in back in to the data array that loads the table
Seems like I have to do this or the data array never gets the type in values.
I edit various rows and when I click to the next row i get the textFieldDidEndEditing for the previous cell as expected. So far so good.
Now the problem. In the last cell I edit the cursor is still in the UITextField. I click a button to 'evaluate' the list of items in the table. Clicking the button to 'evaluate' the table causes its routine to kick off immediately. HOWEVER, the 'evaluate' finishes BEFORE get the final textFieldDidEndEditing for the field where my cursor was sitting.
That is, i do get the textFieldDidEndEditing for the field where my cursor was sitting but I don't see that call back until too late. i have already 'evaluated; the array and then afterwards I stuff the last typed value in to the data array that load the table.
How do I get the 'evaluate' to wait on the last textFieldDidEndEditing (IF there is one to come)? OR what do people typically do? Put in some kind of pause for my 'evaluate' so that there is time for the textFieldDidEndEditing callback to happen first?
I have a separate question on a second but related problem here Know the row number inside custom UITableViewCell - new wrinkle

Related

Getting the data of all TableView Cell which all has TextFields in it (including the hidden views)

I'd like to get every data that is within all cells in one tableview which is quite a long list.
I'm looking for an approach on how to retrieve everything including those hidden in view, which I know the views are reused. I think some of you might have experienced this problem before, what are your approach on this?
I've tried
let cells = self.tableView.visibleCells
then looping into every cell and saving each data to an array but it is not effective in getting those that aren't part of the view or hidden. Is there a way to get over this?
In cellForRowAtIndexPath, YOU are telling the table what is in each cell. So why would you turn around and ask the table what's in each cell? If the user puts "Hello" in your first cell, then scrolls the table enough to push that first cell out of view, then when the user scrolls back to the top, YOU are the one telling it to put "Hello" back in that first cell. YOU own the data source, not the table.
You need a data source. That can be "empty" at first, maybe an array of empty strings if that's what you want (each index in the array could map to a table row for example). But then, as the user interacts with the text fields in the cells, you need to update that data source with the text they entered.
You should use that data source as your source for the cellForRowAtIndex method. That way you can handle populating the cells when they are requested by the table, and you also know all the data when the user is done.
Why not just update the model each time the user taps a key when editing a textfield? You could create a protocol for that cell subclass and make your view controller the delegate for each cell. As long as cells are guaranteed to stay on the screen while you're typing (you'll get some weird behaviors if not) the cell can send a message to the view controller or whatever you hook it up to telling it what new value to store. Then everything is already stored for you when you need the full list, and you don't have to interact with the tableview.

Is it efficient to save text in Core Data in UITextView delegate method textViewDidChange?

I have multiple UITextView instances in my UIViewController and would like to save the typed-in text in Core Data when the view controller's view disappears or a specific button is clicked. Ideally, I would use the textViewDidEndEditing delegate method to save the changes to Core Data but the problem is that if a user changes a text view and then hits the said button, this delegate method is not called. So how should I save the changes?
One option I can think of is to leverage textViewDidChange - but that method is called each time a character is typed in. If I were to save the text to Core Data within this method, wouldn't that be inefficient?
Are there other ways you can recommend for me to achieve this?
It's unclear exactly what the relationship is between button pushing and saving data, but one way would be to leverage viewWillDisappear: and make your Core Data insertions fire once you know the text inputs are final and the user is leaving.
You could fire the same insertion method when the button is tapped.
You may have a local NSString variable to hold the updated value of your string and you can save it to CoreData when you finish your work with screen. It may be on :
- A button touch
- View disappearing
- An error ocured in page
If you do not want to have a save action, you can also set a timer to count the time starting from the last edit moment of textViewDidChange and you can trigger timer if there is no change for the last 3-5 seconds.

textFieldDidEndEditing not called in a tableview inside a navigation controller

I have a tableview controller inside a navigation controller. This table simply shows one textfield in each row. In my navigation controller I have a “Done” navigation item that gets all the values entered in the textfields and shows the next screen.
The tableview controller implements UITextFieldDelegte and textFieldDidEndEditing to store the values of every textfield in its datasource (array of strings). In cellForRowAtIndexPath I also assign the delegate of the text fields to themselves. This all works well if I tap on the different textfields, I see how the datasource is properly updated.
My problem is when I do this sequence: type a value in one text field and then tap on the “Done” navigation item. I see that textFieldDidEndEditing is not called so the value is not stored. I also tried with textFieldShouldReturn and textFieldShouldReturn but nothing.
I have read many similar posts and I think the problem is that the "event" is being caught by prepareForSegue instead of textFieldDidEndEditing. If this is correct, I don’t know how to deal with this since I don’t know how to identify the indexPath of that “last edited textfield” when the Done is tapped.
Another related question: I have seen two approaches to get the indexPath of the cell containing the textfield when textFieldDidEndEditing is called:
1) textField.convertPoint + tableView.indexPathForRowAtPoint
2) tableView.indexPathForCell + textField.superview
Both seem to work well without differences (except for the issue that I just stated). Is any approach better than another?
Many thanks in advance for your help!!!
PS: if possible, in Swift code, please!
On click of done button you can add this line,
[self.view endEditing:YES];
This line will resign your currently active text field, and will call your text field delegates.
If you are displaying all text fields within same table section in that case you can assign indexPath.row to textField.tag, and using that tag you can create indexPath.
This is how you can address this:
Step 1 : Keep track of your active text field. You can keep a strong reference to it and set it whenever a textField is activated. Something like this:
self.inputField = iCell.inputField;
Step 2 : Once your Done button is tapped, add below line in action handler.
[self.inputField endEditing:YES];
PS: Alternatively, you can simply call [self.view endEditing:YES]; without the need to track the current active text field. I, personally, go with keeping reference to textfield as it helps me doing other stuff around current active textfield.

In Swift, how should I save data from a custom view so that it is not deleted when a cell is dequeued?

I have a custom view that exists in a cell in a tableview. The view is called bulletRow and it is a series of bullets that can be filled in or emptied when a user taps on them. Each cell in my tableview contains some bulletRows and I need to save them when the user taps on them. I have considered using Core Data, but I don't need them to persist when the app is shut down, I only need it to exist when the user scrolls past the dequeueing point.
Here is my situation right now: The default state for bulletRows is to have 5 dots, all of them empty. When a user taps on them they become filled. If the user scrolls down however, they get reset back to being empty. How can I save the state of the bulletRows?
The bulletRows have a property called numberOfFilledCircles which can be set at anytime to change the amount of filled in circles. This is all done in Swift as well.
In general, you should use something, such as an array, to hold the state of your table. The cells in your table should reflect that state, and update that state when selected.
You might start with an array of integers in your table view controller, like this:
var numberOfFilledCircles = [Int]()
Use the number of items in your array to determine how many rows to display in your table, by returning numberOfFilledCircles.count from your numberOfRowsInSection method.
You can populate the array in viewDidLoad. If you're hardcoding the rows, you can repeat this statement for as many rows you want:
numberOfFilledCircles.append(0)
Each Int in the array holds the value representing how many circles are filled (initialize to 0).
In your cellForRowAtIndexPath, use the appropriate value from your array when constructing your cell. For example, if your cell had a UILabel called numberOfFilledCircles, you would do this:
cell.numberOfFilledCircles.text = String(numberOfFilledCircles[indexPath.row])
Finally, in your didSelectRowAtIndexPath, update the array with the number of circles you want filled in:
numberOfFilledCircles[indexPath.row] = //whatever you want
The issue here is that the UI is not the model.
When the ui elements are pressed, you should send an action to the underlying model to update its state, and when cells are dequeued you should restore the checkbox state from the appropriate model element.

How to refresh a UITableView in iphone?

I have a UI table view loading data from network. If the user move the finger on one cell, one button will be displayed, just like iPhone style delete button. If the user click this button, the value of one label in the cell will be changed accordingly. However, I didn't find any way to make table view to re-draw this cell, except for reload the whole table. I don't want to use reload data method, because I just need change the value in one cell instead of the whole table. Any suggestion on this?
Take a look at the method
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Calling this method will result in your table view's data source asking its delegate for information about that cell.
For future reference, I found this very easily by checking the documentation on UITableView. I suggest you do that in the future before posting here.

Resources