I've had to deal with something that sounds similar in a UITableView earlier
this week.
FYI, completing an edit by dismissing the keyboard commits the changed data to
the datasource.
Simply tapping a field in a cell invokes editing.
Now, I'm not sure if this is the best way, or the standard way, but it is a
way and it works.
Care needs to be taken as (from what I have seen in iOS 7), certain events are
not sent to the desired objects (UITextField delegates) that you would expect
to be sent, while others are. Notably, these are the events of a text field
starting being edited, a text field ending being edited and a change within a
text field.
As these edits on iOS will be handled through display of a keyboard, and
possibly the clicking of the clear button, we need to make sure that the events
for keyboard display and dismissal are also caught.
According to the research that I have done, if you make a UITableView that is
not fullscreen or is in a UIView and extended by use of UITableView and
UITextField delegates, you will have to register to receive notifications for
all events that are not automatically sent to your view controller.
Like you, all I am checking for right now is this text field is not empty,
but once this condition is in place, it can be changed to be a rule set if you
wish to handle other conditions.
All data that is displayed is linked from a singleton and committed back to it
on the dismissal of the keyboard. A reloadData is then sent to the tableView,
but really should just be sent to the cell.
One other thing is that I wasn't able to easily determine the current field
being edited when receiving the textFieldDidChangeEditing message (if anyone
knows, I'm all ears). This meant adding a property to the VC called
fieldBeingEdited and when the field starts being edited, store a reference to
that field and clear it when editing stops. Actually, since we will be
constantly setting it when editing starts, you could never clear it, but that
just seems sloppy.
To make sure the notifications are caught, I created two methods,
configureForKeyboardDisplayNotifications and configureForTextEditNotifications.
In all the event methods that I care about, I call the updateUIOnEdit to
conditionally format the UITextField's appearance (reddish if invalid, green
border if legit).
These are:
-(void)textFieldDidBeginEditing:(UITextField *)textField;
-(void)textFieldDidEndEditing:(UITextField *)textField;
-(void)textFieldDidChangeEditing; // My custom method that is called as a
result of subscribing to the UITextFieldTextDidChangeNotification
Don't add notifications for the UITextFieldDidBeginEditingNotification and
UITextFieldDidEndEditingNotification, as these are already sent to the
delegate, but for some reason, UITextFieldTextDidChangeNotification is not.
Notice that there is no textfield passed to textFieldDidChangeEditing. I'm not
sure how to get the textField reference from the notification, so this is where
I use the fieldBeingEdited reference to the currently edited textField.
In my cell subclass, I have the formatting code, so the viewController's
updateUIOnEdit calls the cell's formatViewConditionally method.
Upon return to the viewController's class I can issue a reload data just for
that cell.
A nice article to get you started which has a great method for getting a
textField's parent cell is this one:
http://objcsharp.wordpress.com/2013/09/09/editable-uiTableviewcontroller/
Since I'm doing this for a tableView that is not full screen, there will be
issues when the keyboard appears over the bottom cells in the table and the
cells will be obscured by the keyboard. If you haven't tested for this, I'd
certainly check that case. According to Apple docs, the process is to raise
the contentInset for the bottom of the table view and then scrolling the
tableView to the new position using an
atScrollPosition:UITableViewScrollPositionMiddle. In my experience with a
tableView that is not touching the top and bottom of the screen, this fails to
scroll to the desired position using
atScrollPosition:UITableViewScrollPositionMiddle or
atScrollPosition:UITableViewScrollPositionTop and I have had to simply find a
number that works and use that. Just an FYI.
Not sure how this would help in a UINavigationController, but this is what I
have working in an editable UITableView.
How about disabling the back button if the UITextFieldDelegate returns no? Or
simply setting enabled state of the back button to observe what the
UITextFieldDelegate returns?
Cheers.
On Jan 9, 2014, at 7:22 PM, Rick Mann wrote:
What's the right way to validate fields in an editable detail view in a
navigation stack? It seems that the API doesn't really provide a good means
to do so without a lot of contortions, and so I wonder what the intended
behavior is.
Here's what I've got: A UINavigationController stack with a UITableView that
shows a list of