Problem reading the latest value from UITextField before closing the view - cocoa-touch

I have a view that I'm displaying modally to get login information from a user. I have the following setup:
The view controller is a UITableViewController
The table has three cells: username and password fields (both of type UITextField within UITableViewCell) and one simple cell as the login button.
Values are read from UITextField in textFieldDidEndEditing:message
The text fields are identified by different tag values.
The problem
My problem is that when the focus is in a UITextField and user touches the login button, the respective UITextField's textFieldDidEndEditing:message is sent after the didSelectRowAtIndexPath:. Now the issue here is that I'm sending a message of new user credentials to my LoginViewControllerDelegate in the didSelectRowAtIndexPath: and at that time the text field's value is not read yet.
Some Ideas
I have some ideas how to fix this, but I have complications with each of them.
First, I could close the login view and the delegate is notified during the closing, but I want to give the delegate (one who owns this login view) full control and I think it should be the delegate's job to close the login view on successful login (the login view only reads the credentials, the delegate validates these).
Second, I could also read the username or password just before calling the delegate but then I'd have to look up the text fields. If the views are not visible, I think it is wrong to assume that the cells do exist. This is just a big if, but I wan't to make it right. Would it be ok to retain the UITextFields? This way, however, I can't use some custom cell that would itself provide the textfield.
Basically I want the following:
Need for (valid) user credentials is detected, login view is popped up
User inputs the username and password and invokes done.
The delegate validates these credentials. If they do not work, a message is shown and try step 2 again.
Credentials are ok, so close the login view and continue.

After all tricks I finally figured that simply resigning the first responder right before invoking the delegate fixed this. In the table view controller I simply had to add a call:
[[self.view findFirstResonder] resignFirstResponder];
The findFirstResonder is from a category and can be found here.

Try this instead of using third cell as login button. Use a simple button on login view. On that button's IBAction you can validate user input.

You can use a simple view with two textfields and one UIButton. After the button is pressed you can just remove the view from superview by [yourView removeFromSuperview] . You can receive the data from the yourTextfield.text.
I guess this must do the trick

Related

Best way to implement UIPageControl?

In my app I have a registration page for any new users. At the moment Im using UIPageControl on a view controller so that when a user swipes left a new set of textfields are displayed. I have it so that when the user swipes to the left the previous textfields are hidden. I don't think this is the best way of implementing UIPageControl. I would like to implement it in such a way that when the user swipes to the left the new text boxes slide in with the swipe instead of just appearing. Also when the user swipes back i have to make the previous text fields unhidden but then they don't keep the information that the user has already typed into them.
Any ideas of how to best implement UIPageControl or even the best way to implement a registration form like this?
Thanks a million!
If this is a march through a series of forms that the user must fill out in order, you could use instead a UINavigationController (which, indeed, is what is suggested by the Back button already in your interface)...
The real problem, however, seems to be that you are using UIPageViewController incorrectly: if the user is to be able to go back and forth between views and the information previously entered is to be present, it is up to you to use a different view controller for each view and to save the entered information when the user leaves a view controller and to restore it when the user summons that same view controller again.
This is something you would need to do no matter what implementation you choose, because a view controller can always be destroyed when its view is not being seen. Model-view-controller! It is up to you to maintain the model (the data) - do not rely on the mere view to maintain it for you.

Is there a way to show a message (like UIAlertView) from a modal UIPopover?

I have an iPad app that uses a UIPopover from within a UIVIew; I need to show an alert-type message when a certain condition has been met.
The problem is using a UIAlertView from within the UIPopover, when the user taps on a button in the UIAlertView, it also dismisses the UIPopover, which defeats the purpose of the alert.
I tried using UIActionSheets, but they don't display at all, probably because they are not being called from a controller-type view.
Is there a way to circumvent this behavior?
No, and you shouldn't do that. Popovers are supposed to go away as soon as you touch anything else.
You could enlarge the popover slightly and make room for a status message. When the user creates an appointment that overlaps, you could display a message in the status area.
Or, you could dismiss the popover and display an alert with "ok"/"cancel" buttons. The OK button would create the overlapping appointment, and the cancel button would discard it.
You will need some place to save the info from the popover while you are waiting for the user to decide what to do with the alert. Perhaps have the popover pass a message back to the view controller it comes from, and then have the source view controller create the alert, set itself as delegate, and handle the responses from the user.
According to Apple's Human Interface Guidelines, it is OK to display a UIAlertView on top of a popover:
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/MobileHIG/Alerts.html
To quote specifically:
On iPad, don’t display a modal view on top of a popover. With the
possible exception of an alert, nothing should display on top of a
popover.
Displaying a UIAlertView from a popover does not automatically dismiss the popover. There is likely some of your own code being executed which is causing it to dismiss. For example, in a similar situation I had, I found that displaying a UIAlertView was invoking "shouldAutorotate" in my split view controller, and (due to earlier iOS bugs) I had placed code there to dismiss the popover. For iOS7+ this was no longer necessary, so I was able to move this code into willRotateToInterfaceOrientation, where it no longer causes dismissal of the popover upon display of UIAlertView, because in this case, even though "autoRotate" gets called "willRotateToInterfaceOrientation" does not.

Modal UINavigationController hides although not dismisses

Okay, so I'm building an universal iOS app with an initial login view (view controller named LoginVC), just a plain simple UIViewController. If the login is successful the app segues to an navigation controller (MainNavigationVC). I created this segue through the storyboard gui of XCode, so no programmatic creation of the nav controller is done. The nav controller is presented modally in fullscreen, so the rest of the app is run atop the login view, with this nav controller as the centerpiece of everything.
The navigation controller contains a view (with a view controller named UserStartPageVC), and in its navigation bar is a logout button. This button sends an target action to UserStartPageVC, with the goal of dismissing the nav controller thus bringing the user back to the login view.
So far everything works fine. I can login and use the app as intended. But! When I log out and then re-login XCode tells me this:
Warning! Attempt to present <MainNavigationVC: 0x753110> on
<LoginVC: 0x756fcf0> while a presentation is in progress!
I suppose this means that the login view is trying to modally display a MainNavigationVC navigation controller, but another one is already displayed, right? But how? Can a view be presented without showing?
And how can I get rid of the old nav controller when logging out? I've tried several ways of dismissing the modal view, for instance:
from within UserStartpageVC running
[x dismissViewControllerAnimated:YES completion:NULL]
[x dismissModalViewControllerAnimated:YES]
where x is either self, self.parentViewController or self.presentingViewController.
setting the LoginVC as a property in UserStartpageVC and running
[self.loginVC dismissViewControllerAnimated:YES completion:NULL]
and so on.
All of the tested calls actually brings me back to the login screen, so it's kind of working.
Any ideas? Relevant code samples can be provided if necessary, I just couldn't figure out which pieces that were of interest. The seguing to the navigation controller has no code (except for a performSegueWithIdentifier:sender:), and the code for dismissing it is the part I cannot seem to get straight.
As a sidenote. So far this isn't a REAL problem; the app runs, and it IS possible to logout and re-login without any other side-effects than an error message in XCode. But I suppose this will be a memory leak if users logout and login multiple times, and I'm not in the mood of an unnecessary rejection from Apple.
I discovered another way to get the exact same error message. Lucky me!
If you created a segue at one point and had it tied to a button (click button -> new view) and then later give that segue a name and invoke it directly using
[self performSegueWithIdentifier:#"identifierName" sender:self];
then you can get this error because you can effectively trigger the segue twice. I thought making the button invoke an IBAction would turn off the segue I had set up in the first place, but apparently not. Hitting the button triggered the segue twice, but after I deleted the segue and re-created it as a manual segue on the view with the same identifier then I was able to invoke it via the above code and not get the warning message.
Hoopla! My bad.
Seemed I had set up the notification observing from the login API call in a stupid way. For every time the user triggered a login (or re-login), it added itself as an observer for the notification; the result was that it performed one more segue for every time a login was done.
And doing multiple segues at the same time, is... well, obviously bad.

Cocoa-Touch: How to Change View After Input Validation?

I have a single-view application that takes in a username and a password and validates it with the server. After the credentials are validated, I would like the application to go to a different view, which will show some other data.
I only know how to switch views when I have a button (that is, by dragging it to the secondary view and selecting what kind of segue I want to use). But how do I change the view after the credentials are validated?
To give you a more clear idea, here is how my app currently functions:
Text is entered into two fields. Pressing the "Login" button (or the 'done' button on the keyboard) calls a method that validates the entered credentials. If the credentials are valid, then the add should move on. Otherwise, it will pop up a notification saying that the credentials are invalid.
I have everything completed and working. I just need to know how to change the view in the validation method after the given credentials are validated.
There are a number of ways to achieve this; the technique you choose should depend on if you want the validating view controller to "stay around" after you move on. If you want it to stick around, you can actually do it in much the same manner as your storyboard segues from buttons.
In the storyboard, ctrl-drag from the first (validating) view controller to the second to create the segue. Select the segue and use the inspector panel to give it an identifier. Then in your code in the validating view controller, you can do something like this:
[self performSegueWithIdentifier:#"validCredentialsSegue" sender:self];
If you want the originating view controller to "go away", you must look into the architecture of your application flow. Perhaps you want a master view controller "above" the credential's one that is notified via delegation of the successful login and it decides what to do (maybe it's view is the destination view anyway...). Otherwise, I think in the old days people fussed around with setting the window's rootViewController property. I'm confident there are better techniques, though.

Delay navigationController to pop detailView of UITableView

Im looking for some help regarding to put a save like confirmation if some changes where made to a UITextField and UISegmentedControl.
Can I prevent the UINavigationController from pop the view? And then pop based on buttons in a AlertView?
I use the UITextField and UISegmented control to POST data to a webservice.
I perhaps need to use a modalView for this? but wanted first to see if someone have another idea, because I would like to keep navigation clicks down if possible.
Any suggestions for this?
Thanks,
Why not just using a UIAlertView?
EDIT: On second thought, and re-reading your question + comment, I would recommend to use a Modal View with classics OK/Cancel buttons + a UIAlertView(s) for confirmation(s). (UIAlertView "poping" on OK/Cancel is easy to do via UIAlertViewDelegate)
That's what Modal views are for, block UI until some user action has been completed. Like a form. This is how I do all my forms, and how Apple does (just look at the create mail screen for an example, or any form of iOS apps)
Adding a "Magical" action requiring user interaction on the back button of a navigation controller is bad in terms of user experience, if you hit back, you expect the view to pop, nothing else. I would then be surprised if Apple SDK even allows to cancel that event...
You can do what you would like without the need of a modal view.
First, you can use your text field's UITextFieldDelegate to set a flag in your controller when the field content is modified. You can reset this flag when the data is sent out.
Then you could override your UIViewContorller's viewWillDisappear to show an alert to the user in case new data have not been posted at the moment the view is going to disappear and give him the possibility of sending it to the server. This method will be called when you move to a different controller in your navigation UI, and you will not have a chance to "reject" the operation.